skimemo


skimemo - 日記/2019-02-28/ローカルS3互換ストレージサーバーの構築

_ ローカルS3互換ストレージサーバーの構築とリバースプロキシの設定

OSSのZenko(scality/s3server)サーバーの構築記です。
これを立てることで、以下のような事ができます。

  1. Mastodonの画像サーバーを安価に作れる
  2. S3サーバー利用サービスの開発用に使える

まず1のMastodonサーバーについて、本題では無いので簡単に触れて終わりにします。
私の立てているサーバーはさくらのクラウドを使用しています。自宅サーバーもあるのですが、可用性の面でサービス稼働には使用したくありません。一方でMastodonサーバーは画像が数十GB単位で溜まります。これに合わせてさくらの契約を増やしていくと費用が増大してしまいますので、画像サーバーだけ自宅に逃がす、ということができるようになります。

e1.png

というわけで構築手順です。

_ Zenkoサーバーを立てる

dockerを使います。

docker run -v /var/s3/data:/usr/src/app/localData -v /var/s3/metadata:/usr/src/app/localMetadata -v /var/s3/config.json:/usr/src/app/config.json -v /var/s3/authdata.json:/usr/src/app/conf/authdata.json -p 8000:8000 -d --restart=always scality/s3server

これはデータ永続化のため、データ領域をローカルの/var/s3以下に配置している例です。
また、docker再起動時にも自動起動するよう、--restart=alwaysを付けています。何回もこのコマンドを実行すると何個もの自動起動が登録されてしまうので注意です。
2つの設定ファイル、config.jsonauthdata.jsonもローカルにアサインしています。

ますはdockerコンテナにログインし、オリジナルのファイルをコピーしてきます。

# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
cf2d3cf55966        scality/s3server    "/usr/src/app/docker…"   10 hours ago        Up 9 hours          0.0.0.0:8000->8000/tcp   eager_lamport
# docker exec -i -t cf2d3cf55966 /bin/bash
root@cf2d3cf55966:/usr/src/app# cat config.json

各々の設定ファイルは以下の通りです(内容はイメージです(笑))。
■authdata.json

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
{
 "accounts": [{
        "name": "hoge",
        "email": "hoge@example.com",
        "arn": "arn:aws:iam::123456789012:root",
        "canonicalID": "ffe7d7c960958453eaab7f7f349cb6360926943882e7ab45********",
        "shortid": "123456789012",
        "keys": [{
            "access": "bucketname",
            "secret": "password"
        }]
    },
    ]
}

5,7行目は本当にこの通りにしています(元ファイルがこうだった)。

■config.json

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
{
    "port": 8000,
    "listenOn": [],
    "replicationGroupId": "RG001",
    "restEndpoints": {
        "s3.webdb.co.jp": "us-east-1"
    },
    "websiteEndpoints": ["s3-website-us-east-1.amazonaws.com",
                        "s3-website.us-east-2.amazonaws.com",
                        "s3-website-us-west-1.amazonaws.com",
                        "s3-website-us-west-2.amazonaws.com",
                        "s3-website.ap-south-1.amazonaws.com",
                        "s3-website.ap-northeast-2.amazonaws.com",
                        "s3-website-ap-southeast-1.amazonaws.com",
                        "s3-website-ap-southeast-2.amazonaws.com",
                        "s3-website-ap-northeast-1.amazonaws.com",
                        "s3-website.eu-central-1.amazonaws.com",
                        "s3-website-eu-west-1.amazonaws.com",
                        "s3-website-sa-east-1.amazonaws.com",
                        "s3-website.localhost",
                        "s3-website.scality.test",
                        "zenkoazuretest.blob.core.windows.net"],
    "replicationEndpoints": [{
        "site": "zenko",
        "servers": ["127.0.0.1:8000"],
        "default": true
    }, {
        "site": "us-east-2",
        "type": "aws_s3"
    }],
    "backbeat": {
        "host": "localhost",
        "port": 8900
    },
    "cdmi": {
        "host": "localhost",
        "port": 81,
        "path": "/dewpoint",
        "readonly": true
    },
    "bucketd": {
        "bootstrap": ["localhost"]
    },
    "vaultd": {
        "host": "localhost",
        "port": 8500
    },
    "clusters": 1,
    "log": {
        "logLevel": "info",
        "dumpLevel": "error"
    },
    "healthChecks": {
        "allowFrom": ["127.0.0.1/8", "::1"]
    },
    "metadataClient": {
        "host": "localhost",
        "port": 9990
    },
    "dataClient": {
        "host": "localhost",
        "port": 9991
    },
    "metadataDaemon": {
        "bindAddress": "localhost",
        "port": 9990
    },
    "dataDaemon": {
        "bindAddress": "localhost",
        "port": 9991
    },
    "recordLog": {
        "enabled": true,
        "recordLogName": "s3-recordlog"
    },
    "mongodb": {
       "replicaSetHosts": "localhost:27018,localhost:27019,localhost:27020",
       "writeConcern": "majority",
       "replicaSet": "rs0",
       "readPreference": "primary",
       "database": "metadata"
    }
}

ここではrestEndpointsのみを修正しています。
restEndpointsは、どこ向けのアクセスを許可するかを記述します。
バーチャルドメインで複数のサーバー名を持っている場合など、複数の記述が必要です。
なお、ここは1つのポイントで、今回はリバースプロキシを用いてlocalhostからアクセスしますがlocalhostは不要です。理由は次項で。

_ 接続確認

私はCyberDuckを使いましたが、S3 Browserというのもあるようです。
HTTPで接続するにはHTTP Profileが必要です。
この辺は特に難しい事は無いので書きませんが、詳しく知りたい方は以下のサイトがとても参考になります。

Scality S3 Server を試してみる
Scality S3 Server (Object Storage) を使ってみる

_ apacheのproxy設定

当サーバーの運用では、表(おもて)はApacheで受けて、バックエンドとしてZenkoサービスを動かす計画です。従って、zenkoはポート8000で稼働したまま、apacheにリバースプロキシ設定を行います。

e2.png

しかし、実は一番ここで填まりました。ポート8000へ直接アクセスするのはすぐにできるようになるのですが、表にApacheを立ててリバースプロキシの設定をすると、何故か認証エラーになってしまうのです。(この時はconfig.jsonのrestEndpointsにはlocalhostを追記しています)
エラー内容は以下です。

SignatureDoesNotMatch
The.request.signature.we.calculated.does.not.match.the.signature.you.provided.

そこで、8000にアクセスした時と80にアクセスした時の通信内容をtcpdumpで採取して比較してみます。

tcpdump -i lo  port 8000 -X

すると、送信時のHost:ヘッダが異なることが分かりました。

正常時(8000へ直接アクセス):

       0x00b0:  3835 350d 0a48 6f73 743a 2073 332e 7765  855..Host:.s3.we
       0x00c0:  6264 622e 636f 2e6a 700d 0a78 2d61 6d7a  bdb.co.jp..x-amz

異常時(80へアクセス):

       0x0040:  2e31 0d0a 486f 7374 3a20 6c6f 6361 6c68  .1..Host:.localh
       0x0050:  6f73 743a 3830 3030 0d0a 4461 7465 3a20  ost:8000..Date:.

その他Credential情報は同じでした。従って「signature.we.calculated.does.not.match」エラーの原因は、signatureの計算にhost名が使われており、サーバー側で把握しているhost名とクライアント側で思っているhost名が異なるためではないかと予想されました。
そこで、リバースプロキシの設定にProxyPreserveHost Onを足してみます。

■/etc/httpd/conf.d/vhost.conf

#### s3
<VirtualHost 61.206.124.164:80>
   ServerName s3.webdb.co.jp
   RewriteEngine On
   RewriteCond %{HTTP:Upgrade} =websocket [NC]
   RewriteRule /(.*)           ws://localhost:8000/$1 [P,L,NE]
   RewriteCond %{HTTP:Upgrade} !=websocket [NC]
   RewriteRule /(.*)           http://localhost:8000/$1 [P,L,NE]
   ProxyPassReverse / http://localhost:8000/
   ProxyPreserveHost On
</VirtualHost>

内容はほぼRocketChatの引き写しです(笑)。6,8行目のNEは必要な場面があるか分かりませんが付けています(再エンコード禁止)。
アクセス全てをlocalhost:8000へ転送しますが、Host名は書き換えないという設定です。

これでCyberduckからポート80にアクセスしても無事ログインできるようになりました。

httpsは、apacheに通常のSSL設定を行えば後はhttpと同じです。
(最終的にはこう)

e3.png
Category: [Linux] - 07:41:57

20190228_s3.html is not found or not readable.


 
Last-modified: 2019-02-28 (木) 10:42:55 (26d)