架構師教你如何 10 步 Docker 化一個應用

前言java

本文將講解如何將應用 Docker 化的一些很實用的技巧和準則,推薦一讀。python

1、選擇基礎鏡像nginx

每種對應技術幾乎都有本身的基礎鏡像,例如:面試

  • https://hub.docker.com/_/java/
  • https://hub.docker.com/_/python/
  • https://hub.docker.com/_/nginx/

若是不能直接使用這些鏡像,咱們就須要從基礎操做系統鏡像開始安裝全部的依賴。docker

網上大多數教程使用的都是以 Ubuntu(例如:Ubuntu:16.04 )做爲基礎鏡像,這並非一個問題,可是我建議優先考慮 Alpine 鏡像:vim

  • https://hub.docker.com/_/alpine/

Alpine 是一個很是小的基礎鏡像(它的容量大約只有 5MB)。緩存

注:在基於 Alpine 的鏡像中你沒法使用 apt-get 命令。不過你沒必要擔憂,由於 Alpine 系統有本身的軟件包倉庫和包管理工具 apk。關於 apk 的具體使用你能夠詳細參考:「Alpine Linux配置使用技巧」一文。安全

2、安裝必要軟件包性能優化

這個步驟一般比較瑣碎,有一些容易忽略的細節:服務器

  • apt-get update 和 apt-get install 命令應該寫在一行(若是使用 Alpine 則對應的是 apk 命令)。這不是一個常見的作法,可是在 Dockerfile 中應該要這麼作。不然 apt-get update 命令產出的臨時層可能會被緩存,致使構建時沒有更新包信息。(具體可參見此文)。
  • 確認是否只安裝了實際須要的軟件(特別是在生產環境中運行這個容器)。

注:我見過有人在他們的鏡像中安裝了 vim 和其餘開發工具。若是這是必要的,應該針對構建、調試和開發環境建立不一樣的 Dockerfile。這不只僅關係到鏡像大小,還涉及到安全性、可維護性等等。

3、添加自定義文件

一些優化 Dockerfile 的小提示:

  • 理解 COPY 和 ADD 指令的區別,具體可參考此文。
  • 儘量遵守文件系統慣例來存放文件。例如:針對解釋型應用程序(如:Python),使用 /usr/src 目錄。
  • 檢查添加文件的屬性。若是須要可執行權限,沒有必要在鏡像上新建一個層( 經過 RUN chmod +x … 指令來增長權限)。你只須要在代碼倉庫的源文件上修正這些屬性便可,即便開發平臺是 Windows,也能夠參照此文給文件增長可執行權限。

4、定義容器運行時的用戶權限

  • 容器中的進程默認狀況下是以 root 權限運行的。
  • 若是容器中的應用程序須要使用特定的用戶或組(/etc/passwd 或 /etc/group)來運行時,能夠在容器啓動時使用 docker run 命令的 --user 參數來指定其固定的 UID 或 GID。
  • 儘量避免容器中的進程以 root 權限運行。

注:如今很多熱門應用程序鏡像都須要用特定的用戶 ID 來運行(例如:Elastic Search 須要 uid:gid = 1000:1000),請儘可能不要在寫出這樣的鏡像。更多關於容器內運行應用程序的權限說明可參考此文。

5、定義暴露的端口

不要爲了暴露特權端口(例如:80)而將容器以 root 權限運行。若是有這樣的需求,可讓容器暴露一個非特權端口(例如:8080),而後在啓動時進行端口映射。

注:低於 1024 的 TCP / IP 端口號就是特權端口,由於不容許普通用戶在這些端口上運行服務。

6、定義入口點(entrypoint)

  • 普通方式:直接運行可執行文件。
  • 更好的方式:建立一個 docker-entrypoint.sh 腳本,這樣能夠經過環境變量來配置容器的入口點。這也是一個很是廣泛的作法,可參考下面這些例子:elasticsearch 的 docker-entrypoint.sh 文件 和 postgres 的 docker-entrypoint.sh 文件。

7、定義一種配置方式

每一個應用程序都須要參數化,你基本上能夠遵循如下兩個原則:

  • 使用應用程序特定的配置文件:該方式須要經過文檔來講明配置文件的格式、字段、放置位置等等(當運行環境比較複雜,例如:應用程序跨越不一樣的技術,則不太合適)。
  • 使用操做系統環境變量:簡單而有效。這也是 12-factors 推薦的方式。

注:使用環境變量方式並不意味着您須要丟棄配置文件並重構應用程序的配置機制,你只須要經過 envsubst 命令來替換配置文件模板中的值就能夠了(這個流程通常須要在 docker-entrypoint.sh 文件中完成,由於這須要在容器進程運行前完成)。例如:在 Nginx 配置中使用環境變量,具體方法可參考此文。

這種方式能夠將應用程序的配置文件封裝在容器內部。

8、外部化數據

關於數據存儲有一條黃金法則:絕對不要將任何持久化數據保存到容器內。

容器的文件系統自己是被設計成臨時和短暫的。所以任何由應用程序生成的內容、數據文件和處理結果都應該保存到掛載的卷或者操做系統綁定掛載點上(既:將宿主機操做系統的目錄掛載到容器中)。

若是將數據保存到綁定掛載點,對於要綁定到容器的宿主機上的目錄,你須要注意如下幾點:

  • 在宿主機操做系統上建立非特權用戶和組。
  • 全部須要綁定目錄的全部者都是該用戶。
  • 根據使用場景給受權(僅針對這個特定的用戶和組,其餘用戶無權訪問)。
  • 容器也以該用戶運行。
  • 容器能夠徹底控制這些目錄。

9、確保處理好日誌

若是這是一個新的應用程序,而且但願它可以堅持 Docker 約定,就不該該將日誌寫入任何文件。應用程序應該使用標準輸出和標準錯誤輸出日誌,這和以前推薦使用環境變量傳遞參數同樣,這也是 12-factors 之一,具體能夠參見這裏。

Docker 會自動捕捉應用程序的標準輸出,並能夠經過 docker logs 命令查看。有關於 docker logs 的具體使用你能夠參考這裏。

可是在一些實際場景下你可能會遇到問題,例如:運行一個簡單的 Nginx 容器,至少會有兩種不一樣的日誌文件:

  • HTTP 訪問日誌(Access Logs)
  • 錯誤日誌(Error Logs)

對於這種按照特定結構輸出日誌的應用,就不太適合將它們的日誌輸出到標準輸出。這種狀況下,你須要按持久化的方式處理這些日誌,並確保這些日誌文件的能正常的輪轉。

10、輪轉日誌

若是應用程序將日誌寫到文件,或者會無限追加內容到文件,就須要關注這些文件的輪轉(rotation),這對於防止服務器空間耗盡很是有用的。

若是使用綁定掛載,咱們能夠依靠宿主機的一些工具來實現文件輪轉功能。例如:logrotate,關於 logrotate 的使用你能夠參考示例1、示例二。

在此我向你們推薦一個Java高級羣 :725633148 裏面會分享一些資深架構師錄製的視頻錄像:(有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構、面試資料)等這些成爲架構師必備的知識體系 進羣立刻免費領取,目前受益良多!

相關文章
相關標籤/搜索