社内のとあるプロジェクトではAmazon ECSを使用しているのですが、アプリケーションから出力するログはDockerコンテナ内に出力されるため、Amazon EFSに保存できるか試してみました。
ログはCloudWatchにも転送しているのですが、スタックトレースが1行ごとに別のログとして扱われたりいまいち検索しづらいので、従来通りファイルとして扱えないか調べたところ、Amazon EFSに保存できそうなことがわかりました。
Amazon EFSはネットワークファイルシステムという言わばWindowsの共有ドライブのような機能で、複数のサーバーからネットワーク経由で接続することができます。そこで、ECSから出力するログをEFSに保存し、別のEC2にログインしてアクセスできるよう設定してみます。
1.セキュリティグループの作成
EFSへのアクセスのためセキュリティグループを2つ作ります。
EFSへのアクセスにはTCPポート2049(NFS)を使用するのでセキュリティグループで許可を与える必要があります。
コンテナのIPアドレスは変動するので、IPアドレスの代わりにセキュリティグループに対して許可を与えるようにします。
まず、コンテナ用のセキュリティグループを作成します。
(ここではEFSとは関係ないですが動作確認用に8080を開放しています)
次に、EFS用のセキュリティグループを作成し、コンテナ用のセキュリティグループからポート2049番へのアクセスを許可します。(ソースにコンテナ用のセキュリティグループを指定します)
2.EFSの作成
EFSを作成します。
EFSのネットワークの設定から最初に作成したEFS用のセキュリティグループを割り当てます。
3.dockerイメージの準備
docker用のイメージを用意しECRに登録します。
詳細は省略しますが、ここでは動作確認用にTypeScriptでexpressを起動し、アクセスごとにログを出力するアプリを作成します。
ログは /app/log に出力します。
########################################
#index.ts
import express from 'express'
import log4js from 'log4js';
const app = express()
log4js.configure({
appenders: {
file: { type: 'file', filename: 'log/default.log' }
},
categories: {
default: { appenders: ['file'], level: 'all' }
}
});
const logger = log4js.getLogger('default');
const router = express.Router()
router.get('/', (req: express.Request, res: express.Response) => {
logger.info("request: " + req.ip)
res.send("Hello efs-test world. " + new Date())
})
app.use(router)
logger.info("server start")
app.listen(8080)
########################################
Dockerfile
FROM node:14-alpine
WORKDIR app
RUN apk add --no-cache nodejs
ADD package.json .
RUN npm install
RUN mkdir log
ADD index.js .
CMD node index.js
4.ECSのタスクとサービスを作成
ECSのタスクを作成する際にボリュームを作成します。
コンテナを追加しストレージとログのマウントポイントを追加します。
EFSのボリュームとマウントするコンテナ内のディレクトリを指定します。
ECSのタスクにサービスを追加します。
ネットワーク構成で最初に作成したコンテナー用のセキュリティグループを割り当てます。
これにより、コンテナーからEFSにアクセスできるようになります。
なお、セキュリティグループの設定に誤りがありEFSに接続できないとタスクが停止し、タスクの停止理由には以下のようなエラーメッセージが表示されます。
Error response from daemon: create ecs-efs-test-task... : Post http://%2Frun%2Fdocker%2Fplugins%2Famazon-ecs-volume-plugin.sock/VolumeDriver.Create: context deadline exceeded
タスクが起動したらブラウザからアクセスできるか確認します。
5.EC2へのマウント
次に、EFSに出力されているはずのログをEC2から確認します。
まずはEC2にコンテナと同じようにセキュリティグループを割り当て、EFSにNFSで接続できるようにします。
AWS上のUbuntuからEFSに接続するために以下のパッケージを追加します。
sudo apt install rpcbind
sudo apt install nfs-common
EFSのURLを確認します。EFSのネットワークを開くとURLが確認できます。
EFSをマウントしログが出力されているか表示します。
マウントする際にはローカルの空のディレクトリをあらかじめ作成する必要があります。
また、URLに続けてセミコロンとディレクトリ(通常は”/”)を追加します。
アプリケーションにアクセスするたびにアクセスログが出力されれば成功です。
mkdir /opt/efs-test
mount -t nfs4 fs-00000000.efs.ap-northeast-1.amazonaws.com:/ /opt/efs-test
tail -3 /opt/efs-test/default.log
参考
チュートリアル 使用 Amazon EFS ファイル システム Amazon
東京都心在住のフルリモート勤務エンジニア。サーバサイドの開発担当で得意な言語はC#。