最近有收到需求是要將容器的日誌寫入 AWS CloudWatch 中,剛好 docker 的 logging drivers 有支援,紀錄一下過程
docker 預設的 logging driver 是 json-file
,日誌檔案路徑在 /var/lib/docker/containers/<CONTAINER_ID>/<CONTAINER_ID>-json.log
這是 docker 的 logging drivers 支援的清單
logging driver 可以單一容器設定,也可以全域設定 (修改 /etc/docker/daemon.json
)
下面關於 docker 的示範都是使用單一容器設定 logging driver
直接使用 awslogs logging driver
沒有傳遞 AWS Credentials 而直接使用 awslogs logging driver 的話會有下面錯誤
啟動容器
docker run --name test1 \
--log-driver awslogs \
--log-opt "awslogs-region=us-east-1" \
--log-opt "awslogs-group=myLogGroup" \
--log-opt "awslogs-stream=myLogStream" \
busybox echo test1
查看一下狀態
docker container ls --all --filter name=test1
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e8fea7f1ce76 busybox "echo test1" 7 seconds ago Created test1
發現無法啟動容器,容器的狀態是 Created
,表示容器有成功從 Image 創建,但沒有成功啟動
找出錯誤原因
docker container inspect test1 | jq '.[0].State.Error'
failed to initialize logging driver: failed to create Cloudwatch log stream: NoCredentialProviders: no valid providers in chain. Deprecated.
For verbose messaging see aws.Config.CredentialsChainVerboseErrors
設定 AWS CloudWatch Policy
因為日誌要寫入 AWS CloudWatch 中,需要有相對應的 Credentials 及 Policy
Policy 最少需要 logs:CreateLogStream
logs:PutLogEvents
這兩個 action,下面是我的 policy 設定
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogStream", // required
"logs:PutLogEvents", // required
"logs:CreateLogGroup" // 如果沒有給 CreateLogGroup 的話,需要事先建立 log group
],
"Resource": [
"arn:aws:logs:*:*:*"
]
}
]
}
傳遞 AWS Credentials 參數給 docker daemon
有兩種方式傳遞 AWS Credentials
- 在 root 使用者家目錄下新增 AWS shared credentials file
/root/.aws/credentials
- 新增 docker daemon 環境變數
下面過程是使用第二種方式
新增環境變數
sudo mkdir -p /etc/systemd/system/docker.service.d
cat << EOF | sudo tee /etc/systemd/system/docker.service.d/override.conf
[Service]
Environment="AWS_ACCESS_KEY_ID=<YOUR_AWS_ACCESS_KEY_ID>"
Environment="AWS_SECRET_ACCESS_KEY=<YOUR_AWS_SECRET_ACCESS_KEY>"
EOF
或是執行 sudo systemctl edit docker.service
指令,會進入編輯器進行編輯,完成編輯後依然是寫入相同檔案,兩者是一樣的
重新啟動 docker daemon
sudo systemctl daemon-reload
sudo systemctl restart docker.service
測試一下
docker run --name test1 \
--log-driver awslogs \
--log-opt "awslogs-region=us-east-1" \
--log-opt "awslogs-group=myLogGroup" \
--log-opt "awslogs-stream=myLogStream" \
busybox echo test1
會在 CloudWatch 中看到 test1
的結果
參考資料: