Docker 現在已經是可以當 production server 用的工具了,來聊一下他對 logs 有哪些配置方式。
根據 docker 官方文件,目前有以下幾個配置方法:
| Driver | 說明 |
|---|---|
| none | 容器沒有可用的日誌,且 docker logs 不會返回任何輸出。 |
| local | 日誌以一種為了最小化開銷而設計的自定義格式儲存。 |
| json-file | 日誌格式為 JSON。Docker 的預設日誌驅動程式。 |
| syslog | 將日誌消息寫入 syslog 設施。主機上必須運行 syslog 守護程序。 |
| journald | 將日誌消息寫入 journald。主機上必須運行 journald 守護程序。 |
| gelf | 將日誌消息寫入 Graylog 擴展日誌格式 (GELF) 端點,如 Graylog 或 Logstash。 |
| fluentd | 將日誌消息寫入 fluentd(轉發輸入)。主機上必須運行 fluentd 守護程序。 |
| awslogs | 將日誌消息寫入 Amazon CloudWatch Logs。 |
| splunk | 使用 HTTP 事件收集器將日誌消息寫入 Splunk。 |
| etwlogs | 將日誌消息寫入 Windows 事件追蹤 (ETW) 事件。僅適用於 Windows 平台。 |
| gcplogs | 將日誌消息寫入 Google Cloud Platform (GCP) Logging。 |
如果你能擁有自己的 log server,會建議把 log 打進 log api server,擁有權限的人就可以在 web tool 上做所有的查詢以及決定資料怎麼保留跟處理,畢竟如果 log 停留在各 server,以現在很多服務走 HA 或是 k8s 情況下,遇到狀況你到底要進哪台服務查詢都會成為問題。
不過現實生活中很多人都只有一台 server,而且也沒有 api log server 這種資源,只是要有 log 即可的話,我們一般會用 json-file 這個選項,這也是 docker 預設的 log driver。
docker-compose json-file 範例
services:
nginx:
image: nginx
container_name: nginx
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
這個範例會把 nginx 的 log 儲存到 /var/lib/docker/containers/<container-id>/<container-id>-json.log,當 log 檔案大小超過 10MB 時,docker 會自動將舊的 log 檔案重新命名為 <container-id>-json.log.1,並開始寫入新的 log 檔案,最多會保留 3 個 log 檔案,當你使用指令 docker logs 時,docker 會自動讀取最新的 log 檔案,並顯示在終端機上。
一般 image 如 nginx,他會把 log 設定成 stdout,這樣 docker 才能夠讀取到 log,然後寫入到你設定的 log driver 裡面,選擇 json-file 時 docker 會自動幫你把 stdout 或 stderr 的 log 轉成 json 格式,然後寫入到你設定的 log driver 裡面。
nginx 的話,他的配置會是這樣:
access_log /dev/stdout;
error_log /dev/stderr;
這樣的缺點是,access log 會跟 error log 都寫在同一個檔案裡面,會造成你在查詢 log 的時候不方便,假設我們想要使用 docker,又想要產生跟傳統 web server 一樣的 log,我們可以修改 nginx.conf,讓他把 log 寫到 /var/log/nginx/access.log 和 /var/log/nginx/error.log。
Nginx Config 範例
nginx.conf
http {
server {
listen 80;
server_name localhost;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
}
}
然後把 log 目錄掛載出來。
docker-compose.yml
services:
nginx:
image: nginx
container_name: nginx
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
- ./logs:/var/log/nginx
我們在 /etc/logrotate.d/nginx 新增一個檔案,然後把以下的內容貼上去:
logrotate conf
/var/log/nginx/*.log {
daily
missingok
rotate 7
compress
notifempty
sharedscripts
lastaction
docker exec nginx nginx -s reopen
endlaction
}
docker exec nginx nginx -s reopen 的用意是 logrotate 在 rotate 之後需要呼叫 docker 重新開啟 nginx 的 log,不這樣的話 nginx in docker 會使用你 rename 後的 log 檔案繼續寫 log。
當我們使用 compress,並且會針對壓縮過後的檔案做後續處理的話,一定要有 sharedscripts 以及使用 lastaction,如果使用 postrotate 的話,他不會等所有的檔案都執行完壓縮就直接作動了。
這邊有幾個 logrotate 的指令可以使用:
| 指令 | 說明 |
|---|---|
| prerotate/endscript | 在進行日誌輪轉之前執行的指令,每個匹配的日誌檔案都會執行一次 |
| postrotate/endscript | 在進行日誌輪轉之後執行的指令,每個匹配的日誌檔案都會執行一次 |
| firstaction/endscript | 在所有匹配日誌檔案進行輪轉之前執行的指令,只執行一次 |
| lastaction/endscript | 在所有匹配日誌檔案進行輪轉之後執行的指令,只執行一次 |
| preremove/endscript | 在舊的日誌檔案被移除之前執行的指令 |
另外有一種不用重新開啟檔案的配置參數 copytruncate,這個參數會在 logrotate 開始 rotate 的時候複製原本的 log 檔案,然後 truncate 原本的 log 檔案,這樣 nginx 就不需要重新開啟檔案了,但這樣有機會漏寫紀錄,所以不建議使用這個參數。
Apache2 Config 範例
apache2 的原始 log 配置會是:
ErrorLog /proc/self/fd/2
CustomLog /proc/self/fd/1 common
我們要修改成:
ErrorLog /var/log/apache2/error.log
CustomLog /var/log/apache2/access.log combined
然後把 log 目錄掛載出來。
docker-compose.yml
services:
apache2:
image: httpd
container_name: httpd
ports:
- "80:80"
volumes:
- ./httpd.conf:/usr/local/apache2/conf/httpd.conf
- ./logs:/var/log/apache2
httpd.conf
<VirtualHost *:80>
ServerName localhost
DocumentRoot /var/www/html
ErrorLog /var/log/apache2/error.log
CustomLog /var/log/apache2/access.log combined
</VirtualHost>
logrotate conf
/var/log/apache2/*.log {
daily
missingok
rotate 7
compress
notifempty
sharedscripts
lastaction
docker exec apache2 apachectl -k graceful
endscript
}
這個範例跟 nginx 的範例一樣,只是把 nginx -s reopen 改成 apachectl -k graceful。
假設你 logrotate 後要執行其他 bash 做其他處理的話。
/var/log/apache2/*.log {
daily
missingok
rotate 7
compress
notifempty
sharedscripts
lastaction
docker exec httpd apachectl -k graceful
/usr/bin/bash /usr/local/bin/other_script.sh
endscript
}
沒有留言:
張貼留言