現代程式設計師必須掌握的:Dockerfile 與 Compose 環境搭建學習筆記(二)

2021-03-02 Go語言中文網

上一篇文章對整體結構進行了簡單記錄,這一篇介紹下關於Dockerfile自定義鏡像以及各個服務的配置。

其實 https://hub.docker.com/ 上面各種基礎鏡像非常完善,特別是官方的鏡像質量非常之高,而我再搗騰一次完全是為了讓自己掌握 Dockerfile 方面的技能而已。

在選擇基礎鏡像方面,推薦使用 Alpine ,然後再它上面進行定製,因為它非常的小僅3M。我的 Nginx/Redis 是在 Alpine 基礎上定製的,PHP 是在 CentOS7上面進行的定製。截圖大家可以感受下大小:

Dockerfile 與 Compose 建立關聯

關於概念可以看這裡:
https://yeasy.gitbooks.io/docker_practice/content/image/build.html

我這裡以 PHP/Redis/Nginx 的定製來進行一些說明(我也只是現學現用,希望高手多指教)。

在上篇的 docker-compose.yml 文件中如下的配置:

dev.nginx.srv:
   image: lei_nginx:1.14.0
   build: ./nginx
   volumes:
       - ./nginx/conf:/home/work/app/nginx/conf
     - ./www:/home/work/www
   ports:
       - "80:8080"
     - "443:443"
   restart: always

這裡重要的是多了 build 這個選項,設置的對應目錄中可以找到 Dockerfile 這個文件,當我們 docker-compose up 時,docker會根據這個文件去先創建鏡像,然後啟動一個容器。

Dockerfile 如何寫

網絡上有非常多關於 Dockerfile 該如何寫的最佳實踐,我覺得有幾點特別重要:

更多最佳實踐可以看這裡:
https://yeasy.gitbooks.io/docker_practice/content/appendix/best_practices.html

接下來以 Redis 的 Dockerfile 來聊一聊實際如何編寫。

FROM alpine:3.7

# 解釋信息
LABEL maintainer="HeLei <dayugog@gmail.com>"

ENV REDIS_VERSION=3.2.11 \
   SRC_DIR=/home/work/src \
   DATA_DIR=/home/work/app/redis/data \
   CONF_DIR=/home/work/app/redis/conf

# 設置系統時區
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone

COPY src/ $SRC_DIR

# 編譯文件
RUN set -ex; \
   \
   addgroup -S work && adduser -S -G work work; \
   apk add --no-cache --virtual .build-deps \
           coreutils \
           gcc \
           jemalloc-dev \
           linux-headers \
           make \
           musl-dev \
       ; \
   \
   cd $SRC_DIR; \
   tar xvzf redis-$REDIS_VERSION.tar.gz; \
   cd redis-$REDIS_VERSION; \
   make && make install; \
   apk del .build-deps; \
   \
   mkdir -p $DATA_DIR && mkdir -p $CONF_DIR; \
   chown -R work:work /home; \
   rm -rf $SRC_DIR

# 拷貝配置文件
COPY conf/ /home/work/app/redis/conf

COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]

# 導出埠
EXPOSE 6379
# 啟動redis
CMD ["redis-server"]

第一行 FROM 用來指定基礎鏡像。也就是你要在什麼鏡像上進行定製,我這裡選擇的是 alpine,這是一個提供的基礎空白對象非常小。只是它上面的包管理是 apk ,使用時需要掌握下它的一些參數。

LABEL可以理解成添加一些說明、描述信息。我這裡僅添加了自己的聯繫方式。可以通過反斜線 \ 來進行換行。

ENV用來設置環境變量,例如:定義一些系統版本、路徑的環境變量,在後續RUN中可以使用(當然不僅僅是RUN中可用),也可以用改寫原有的環境變量,例如:PATH。

RUN這是一個非常重要的命令,它是用來執行命令行的命令。就像上面看到的用 yum 安裝更新軟體,make編譯代碼等。可以通過反斜線 \ 來進行換行。

COPY它是將宿主機的內容複製到容器中指定的路徑。

EXPOSE指令用於指定容器將要監聽的埠。一般設置為應用程式使用常見的埠,例如Redis設置為:6379

現在重點說下 CMDENTRYPOINT 兩個命令。如果Dockerfile中沒有 ENTRYPOINT 選項,CMD 的內容就相當於直接執行某個命令。但是當存在時就是另外一回事。以上面的為例:

COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]

# 啟動redis
CMD ["redis-server"]

這裡設置了一個 ENTRYPOINT ,像上面這種情況的時候如果直接啟動一個容器時,相當於最後應用啟動執行的命令是:./docker-entrypoint.sh redis-server。

根據這個特性,docker-entrypoint.sh 內部可以根據相關參數進行特殊處理。來看下我的 docker-entrypoint.sh 腳本內容

#!/bin/sh
set -e

cd `dirname $0`

# 對文件夾進行權限修改
if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then
   chown -R work:work /home
 exec redis-server /home/work/app/redis/conf/redis.conf
fi

exec "$@"

可以看到如果腳本後面帶的參數是redis-server則會先進行相關目錄授權,然後啟動redis。如果不是就會直接執行,例如:

➜ ~/dockerEnv >docker run -it --rm redis:3.2.11 redis-cli -v
redis-cli 3.2.11

會直接執行後面這個命令,你可以看到redis客戶端的版本信息。這也就是表示,可以把鏡像當成一個命令來使用了。

有了 ENTRYPOINT 這個功能,可以用它在服務啟動時,做更多操作 。例如可以結合 docker-compose.yml 中設置的環境變量做更多事情。可以查看官方的MySQL的 docker-entrypoint.sh 文件內容。

依據Dockerfile啟動容器

Dockerfile 已經寫好了,通過下面的命令即可創建鏡像啟動容器。

➜ ~/dockerEnv >docker build -t lei_redis:3.2.11 .

在 redis/ 目錄下執行上面的命令,他會先獲取基礎鏡像,然後根據命令逐條執行,完成redis的編譯、安裝以及相關清理工作。

編譯完成後可用通過docker image ls查看當前的鏡像列表數據。

然後通過 docker run -it -p 6379:6379 -d lei_redis:3.2.11 啟動一個容器。

啟動完成後,大家可以用redis客戶端連結查看redis已經正常啟動。

當然還有 PHP/Nginx 的鏡像定製,以及每個服務的配置,大家可以在github上查看詳情,這裡就不再贅述了,剩下再介紹下這個過程中遇的到的幾個錯誤。

遇到的錯誤

1. 在宿主機中無法連接Redis
這是由於bind的問題。以前在 vagrant 中安裝redis也遇到過, 通過將配置修改為:

bind 0.0.0.0

宿主機能夠連接到伺服器上。這樣設置的含義是,讓容器中的Redis監聽容器ip的所有埠。這樣設置而不是指定ip是因為每個鏡像可以啟動多個容器,而每個容器的ip地址是不確定的。

2. 鏡像創建時報錯
報錯信息如下:

ERROR: for dockerenv_dev.php-fpm.srv_1  Cannot start service dev.php-fpm.srv: OCI runtime create failed: container_linux.go:348: starting container process caused "exec: \"docker-entrypoint.sh\": executable file not found in $PATH": unknown

這個問題主要是:我的 docker-entrypoint.sh 文件沒有可執行權限,因此在鏡像創建完後,執行ENTRYPOINT指定的腳本時導致錯誤,解決辦法當然很簡單,直接執行:chmod +x docker-entrypoint.sh。然後需要重新創建鏡像。

3. Nginx 無法連接php-fpm
這個錯誤其實與宿主機無法連接Redis很像,錯誤信息:

2018/06/13 11:13:26 [error] 5#0: *8 connect() failed (111: Connection refused) while connecting to upstream, client: 172.18.0.1, server: localhost, request: "GET / HTTP/1.1", upstream: "fastcgi://172.18.0.2:9000", host: "localhost"

修改 php-fpm 的監聽地址為:0.0.0.0:9000,Nginx可正常啟動。

    4. 訪問php文件時找不到文件

    這個錯誤其實與宿主機無法連接Redis很像,執行動態文件時,出現了文件找不到的提示,具體錯誤信息:

2018/06/13 11:21:20 [error] 5#0: *10 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 172.18.0.1, server: localhost, request: "GET / HTTP/1.1", upstream: "fastcgi://172.18.0.2:9000", host: "localhost"

由於Nginx與PHP沒有部署在同一個容器中,相關的項目文件只與Nginx進行了共享,而沒有與PHP的容器進行共享。因此當訪問靜態文件時,Nginx直接在自己的容器中完成操作,而訪問php文件時信息傳到了PHP所在的容器,容器內部無法找到對應的php文件而導致的錯誤。

總結

經過2天的折騰,算是基本把環境搭建起來了。不過還有一些其他問題需要思考該如何進行:

後續會繼續摸索分享自己的經驗。

項目地址:
https://github.com/helei112g/docker-env

喜歡本文的朋友,歡迎關注「Go語言中文網」:

Go語言中文網啟用微信學習交流群,歡迎加微信:274768166

參考資料:

https://yeasy.gitbooks.io/docker_practice/content/

https://docs.lvrui.io/2017/06/09/%E7%BC%96%E5%86%99docker-entrypoint-sh%E5%85%A5%E5%8F%A3%E6%96%87%E4%BB%B6/

https://pkgs.alpinelinux.org/packages

相關焦點

  • 雲計算核心技術Docker教程:Compose使用
    Compose 使用的三個步驟:1.使用 Dockerfile 定義應用程式的環境。2.使用 docker-compose.yml 定義構成應用程式的服務,這樣它們可以在隔離環境中一起運行。3.最後,執行 docker-compose up 命令來啟動並運行整個應用程式。
  • 【長篇博文】Docker學習筆記與深度學習環境的搭建和部署(二)
    歡迎關注我的csdn:原始碼殺手我的CSDN上一篇文章:Docker學習筆記與深度學習環境的搭建和部署(一)https://blog.csdn.net/weixin_41194129/article/details/113823982【長篇博文】Docker學習筆記與深度學習環境的搭建和部署
  • Docker再體驗之Docker Compose,及它與Kubernetes的區別
    /local/bin/docker-composedocker-compose -v 最後能看到版本信息,就是安裝好了,有人可能會遇到一個錯誤。[53396] Cannot open self /usr/local/bin/docker-compose or archive /usr/local/bin/docker-compose.pkg。刪除掉/usr/local/bin/docker-compose,重新下載一下,可能是網絡原因下載有中斷情況,而這個文件又仍然會生成。
  • Docker集群管理之Docker Compose
    安裝Docker Compose可以通過下載二進位可執行文件的方式安裝Docker ComposeDocker Compose的工程配置文件默認為docker-compose.yml,可通過環境變量COMPOSE_FILE或-f參數自定義配置文件,其定義了多個有依賴關係的服務及每個服務運行的容器。以下是一個簡單的配置文件:
  • 雲計算核心技術Docker教程:Docker Compose yml常用配置指令簡介
    Docker Compose 默認使用文件名 docker-compose.yml,例如以下就是一個docker-compose.yml文件示例:version:指定本 yml 依從的 compose 哪個版本制定的services:用於定義不同的應用服務,上例中分別定義了兩個服務
  • 用 Docker 構建 MySQL 主從環境
    前言本篇文章記錄我使用 docker-compose 以及 dockerfile 來構建基於 binlog 的 MySQL 主從環境。如果你嚴格按照文中的步驟進行配置,相信很快就可以搭建好一個基礎的 MySQL 主從環境。
  • 雲計算核心技術Docker教程:docker-compose 常用命令介紹
    在下載安裝Docker Compose後通過創建 Dockerfile 文件就可以使用Docker Compose命令構建和啟動應用了,本文主要介紹docker-compose的常用命令。1.重啟項目中的服務。
  • 用Docker 搭建Web服務環境
    除了鏡像和容器之外,還有兩個概念需要了解一下的,那就是倉庫和 docker-compose。Docker 倉庫是存放鏡像的地方,我們可以從 Docker 倉庫中拉取鏡像到本地,然後再基於鏡像創建容器。docker-compose 是管理容器的。
  • Docker Compose 1.21.0 發布,多容器應用編排
    新版本帶來了一些新特性,以及 bug 修復:Compose file version 2.4Introduced version 2.4 of the docker-compose.yml specification.
  • 雲計算核心技術Docker教程:docker-compose up命令介紹
    在下載安裝Docker Compose後通過創建 Dockerfile 文件就可以使用Docker Compose命令構建和啟動應用了,本文主要介紹docker-compose up命令。命令格式:docker-compose up [options] [--scale SERVICE=NUM...] [SERVICE...]
  • 雲計算核心技術Docker教程:Docker Compose指定單個compose文件
    docker-compose可以使用該-f標誌通過命令行或通過在外殼程序或環境文件中設置COMPOSE_FILE環境變量來指定不在當前目錄中的Compose文件的路徑。
  • 雲計算核心技術Docker教程:Docker Compose編寫CLI環境變量
    可以使用幾個環境變量來配置Docker Compose命令行行為。以開頭的變量與DOCKER_用於配置Docker命令行客戶端的變量相同。如果使用docker-machine,則eval "$(docker-machine env my-docker-vm)"命令應將它們設置為正確的值。(在此示例中,my-docker-vm是您創建的計算機的名稱。)COMPOSE_PROJECT_NAME設置項目名稱。啟動時,此值與服務名稱一起添加到容器中。
  • 【長篇博文】Docker學習筆記與深度學習環境的搭建和部署(一)
    歡迎關注我的csdn:原始碼殺手docker學習筆記本文的最終目的是在docker下搭建深度學習環境,之前的所有操作是簡單對docker的一些實現流程進行記錄,不做更細緻的分析。以下是在搭建深度學習環境之前所做操作。
  • 如何用docker-compose安裝mongo並實現授權登錄和初始化數據
    我們在使用docker-compose安裝mongo的時候,有時需要實現:1、遠程授權登錄;2、資料庫初始化的時候需要初始化一些數據;那麼如何實現上述功能呢?一、準備1.1 建立對應的目錄結構1.2 我們把上述目錄建立在data目錄中mkdir /data創建docker-compose.yml文件
  • Docker 搭建 Redis Cluster 集群環境
    使用 Docker 搭建 Redis Cluster,最重要的環節就是容器通信的問題,這一塊我們在之前的文章中已經給大家解決了《Docker 網絡模式詳解及容器間網絡通信》,本篇文章主要練習使用多個容器完成 Redis Cluster 集群環境的搭建,順便為學習 Docker Compose 鋪鋪路。
  • 雲計算核心技術Docker教程:docker Stack介紹
    docker stack和docker-compose使用方式相同,但是為什麼引入docker stack技術呢。兩者的使用方式,命令如下:$ docker-compose -f docker-compose up$ docker stack deploy -c docker-compose.yml somestackname兩機制都能操縱 compose.yml
  • IT工程師都需要掌握的容器技術之Dockerfile
    Dockerfile 是一個用來構建鏡像的文本文件,文本內容包含了一條條構建鏡像所需的指令和說明,每條指令對應Linux下面的一條命令。docker能夠讀取dockerfile的指令進行自動構建容器,基於dockerfile製作鏡像,每一個指令都會創建一個鏡像層,即鏡像層是多層疊加的,不過鏡像層數越多,效率越低。
  • 雲計算核心技術Docker教程:Docker Compose run命令詳解
    -e KEY=VAL 設置環境變量參數,可以使用多次-l, --label KEY=VAL 添加或覆蓋一個標籤(可以多次使用)-u, --user="" 指定運行的用戶--no-deps 不啟動link服務,只啟動run的服務.--rm 運行後刪除容器,後臺運行模式除外(-d).
  • 雲計算核心技術Docker教程:使用harbor搭建私有鏡像倉庫
    之前介紹的docker搭建私有鏡像倉庫是使用的官方提供的私有倉庫registry,安裝使用雖然簡單,但在管理的功能上存在不足。Harbor是一個用於存儲和分發Docker鏡像的企業級Registry伺服器,作為一個企業級私有Registry伺服器,Harbor提供了更好的性能和安全。
  • 利用雲伺服器搭建解鎖免費聽網易雲灰歌曲的代理-docker版
    註:本教程僅作為學習參考使用,請支持正版一、最近在GitHub上發現一個有趣的項目:UnblockNeteaseMusic,可以解鎖網易雲灰色歌曲,利用docker超簡單搭建。二、搭建步驟1、 yum install docker -y ###安裝docker2 、 systemctl start docker ####啟動docker3、systemctl enable docker #########默認開啟3、yum install python-pip ######安裝pip4、pip