花了好多天的時間在研究,然後終於稍微搞清楚想要將 AWS ECS 上的應用程式的 log 導去 Splunk 時,需要注意的地方有哪些,以及它導出時是怎麼做的。不過在紀錄之前要先提一下,這篇當中不會提到如何建置 Splunk 服務,因為在我的狀況中 Splunk 是其他公司內的團隊已經建好的。
ECS Service 的 Log
首先先談一下為什麼會有想要把 ECS 的 log 導去 Splunk 的需求呢?因為在 ECS 上的服務基本上應該都會想要用 auto-scaling,但 auto-scale 之後帶來的困擾就是 log 四散各地,而且更重要的是 log 會在 container 裡,一旦 container 因為 scale-in 關閉的話,log 就跟著一起消失了。因此,我們自然會想要把 log 導出來存到其他地方去。當然我們是可以選擇 AWS CloudWatch,只是這邊的選擇是 Splunk,因為 Splunk 提供了比較強大的 log 搜尋功能(當然也比較貴就是了)。
Docker Log Driver
AWS ECS 是基於 Docker 的服務,因此腦筋自然就動到了如何利用 Docker 自身的功能來達成這件事?而 Docker 官方的解答就是透過 Docker Log Driver。Docker 預設的 Log Driver 是 json-file
,也就是 Docker 裡的 log 會被寫成一個 JSON 格式的檔案,讓我們之後可以透過 docker logs
指令來查閱那些 log。而我們這裡的目標是要把 log 輸出到 Splunk,因此會需要使用的自然是 Splunk 的 Log Driver [1] 了。
談到這裡,也許腦袋比較靈活的人會先想到一個問題:「container 裡有這麼多資訊,Docker Log 會紀錄哪裡的資訊?」沒錯,這其實就是最重要的問題,也是害我花了幾天的時間搞到死魚眼的問題,因為我一直沒有搞清楚 Docker Log 到底是在看哪裡的 log…..。參考 Docker 的官方文件 [2],其實它是有某種程度提供了完整的描述,不過可能需要對 Linux 系統再熟悉一點吧,我當初看這段描述時並沒有意會到最重要的事情…。
By default,
docker logs
ordocker service logs
shows the command’s output just as it would appear if you ran the command interactively in a terminal. UNIX and Linux commands typically open three I/O streams when they run, calledSTDIN
,STDOUT
, andSTDERR
.STDIN
is the command’s input stream, which may include input from the keyboard or input from another command.STDOUT
is usually a command’s normal output, andSTDERR
is typically used to output error messages. By default,docker logs
shows the command’sSTDOUT
andSTDERR
.
從官方文件的描述可以看到,docker logs
會輸出 STDOUT
和 STDERR
的訊息,換句話說,我們只要把訊息送進 STDOUT
或者 STDERR
,我們就能夠從 docker logs
看到那些訊息,也就能期待 Docker Log Driver 幫我們把訊息轉送到 Splunk。但接下來還有個問題,在 Linux 中所有 process 都有自己的 STDOUT
和 STDERR
,哪個才是 Docker Log Driver 會觀察的對象?這個問題目前我還沒直接從文件上看到,是公司同事提醒說 docker logs
只會看 main process 輸出的
STDOUT
和 STDERR
。而何謂 main process 則可以參考到 [3]。
A container’s main running process is the
ENTRYPOINT
and/orCMD
at the end of theDockerfile
.
這樣看下來大概就可以搞懂整個 Docker Log Driver 的運作形式了。當我用 Dockerfile 啟動 Docker,main process 就會留在 Dockerfile 中的最後一個指令上,也就是 main process 就是讓 Docker 維持運行的進入點。
Dockerfile 與 Docker Logs 的關聯
接下來回到主題,當我想要把 log 輸出到 Docker Log Driver 時,具體來說我該做什麼呢?很明確地,我需要讓 log 出現在 container 的 main process 的 STDOUT
裡。舉例來說,假設我寫了一個 Java 程式,程式本身不會結束(例如是個 Spring Boot Application,所以有內嵌 Embedded Web Server),那麼我只要在 Dockerfile 的尾巴寫上執行 Java 的指令,就可以達成這個目的了:
FROM openjdk:8-alpine ...(略)... RUN java -jar my-spring-boot-app.jar
但如果原本我的最後一行程式是像是 service tomcat start
這種會開背景程序的指令,那麼問題就略為麻煩一點~目前我採取的策略是用 tail
來保證。例如在最後一行執行一個 script,然後 script 的內容是這樣:
while : do tail -F <path_to_log_file> | while read line; echo $line; done done
也就是說,我的背景程序假設它會輸出所有的 log 到某個檔案,那我就在 Dockerfile 中啟動那個背景服務後,最後開一個 tail
的程序一直去看那個檔案,並且把看到的東西都印出來,這樣就能讓檔案的內容一直被輸出到 main process 的 STDOUT
了。
沒有留言:
張貼留言