日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747


「系統架構」如何使用Dockerfile制作Docker容器?(2)

 

接著文章「系統架構」如何使用Dockerfile制作Docker容器?(1)我們繼續介紹ENV、ARG、VOLUME、EXPOSE、WORKDIR、USER、HEALTHCHECK、ONBUILD幾個命令。

7、ENV

這個指令很簡單,就是設置環境變量而已,無論是后面的其它指令,如 RUN,還是運行時的應用,都可以直接使用這里定義的環境變量。

它的格式有兩種:

  • ENV <key> <value>
  • ENV <key1>=<value1> <key2>=<value2>...
ENV NODE_VERSION 7.2.0

RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" 
  && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" 
  && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc 
  && grep " node-v$NODE_VERSION-linux-x64.tar.xz$" SHASUMS256.txt | sha256sum -c - 
  && tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 
  && rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt 
  && ln -s /usr/local/bin/node /usr/local/bin/nodejs

ADD、COPY、ENV、EXPOSE、LABEL、USER、WORKDIR、VOLUME、STOPSIGNAL、ONBUILD等命令都支持環境變量展開。

8、ARG

和ENV命令一樣,ARG命令也是設置環境變量。所不同的是,ARG 所設置的構建環境的環境變量,在將來容器運行時是不會存在這些環境變量的。但是不要因此就使用 ARG 保存密碼之類的信息,因為 Docker history 還是可以看到所有值的。

ARG的格式為:ARG <參數名>[=<默認值>]

Dockerfile 中的 ARG 指令是定義參數名稱,以及定義其默認值。該默認值可以在構建命令 docker build 中用 --build-arg <參數名>=<值> 來覆蓋。

在 1.13 之前的版本,要求 --build-arg 中的參數名,必須在 Dockerfile 中用 ARG 定義過了,換句話說,就是 --build-arg 指定的參數,必須在 Dockerfile 中使用了。如果對應參數沒有被使用,則會報錯退出構建。從 1.13 開始,這種嚴格的限制被放開,不再報錯退出,而是顯示警告信息,并繼續構建。這對于使用 CI 系統,用同樣的構建流程構建不同的 Dockerfile 的時候比較有幫助,避免構建命令必須根據每個 Dockerfile 的內容修改。

9、VOLUME

此命令用來定義匿名卷。之前我們說過,容器運行時應該盡量保持容器存儲層不發生寫操作,對于數據庫類需要保存動態數據的應用,其數據庫文件應該保存于卷(volume)中。

為了防止運行時用戶忘記將動態文件所保存目錄掛載為卷,在 Dockerfile 中,我們可以事先指定某些目錄掛載為匿名卷,這樣在運行時如果用戶不指定掛載,其應用也可以正常運行,不會向容器存儲層寫入大量數據。

它的格式為:

  • VOLUME ["<路徑1>", "<路徑2>"...]
  • VOLUME <路徑>
VOLUME /data

這里的 /data 目錄就會在運行時自動掛載為匿名卷,任何向 /data 中寫入的信息都不會記錄進容器存儲層,從而保證了容器存儲層的無狀態化。當然,運行時可以覆蓋這個掛載設置。比如:

docker run -d -v mydata:/data xxxx

在這行命令中,就使用了 mydata 這個命名卷掛載到了 /data 這個位置,替代了 Dockerfile 中定義的匿名卷的掛載配置。

10、EXPOSE

EXPOSE 指令是聲明運行時容器提供服務端口,這只是一個聲明,在運行時并不會因為這個聲明應用就會開啟這個端口的服務。在 Dockerfile 中寫入這樣的聲明有兩個好處,一個是幫助鏡像使用者理解這個鏡像服務的守護端口,以方便配置映射;另一個用處則是在運行時使用隨機端口映射時,也就是 docker run -P 時,會自動隨機映射 EXPOSE 的端口。

要將 EXPOSE 和在運行時使用 -p <宿主端口>:<容器端口> 區分開來。-p是映射宿主端口和容器端口,換句話說,就是將容器的對應端口服務公開給外界訪問,而 EXPOSE 僅僅是聲明容器打算使用什么端口而已,并不會自動在宿主進行端口映射。

11、WORKDIR

WORKDIR 指令可以來指定工作目錄(或者稱為當前目錄),以后各層的當前目錄就被改為指定的目錄,如該目錄不存在,WORKDIR 會幫你建立目錄。

之前提到一些初學者常犯的錯誤是把 Dockerfile 等同于 Shell 腳本來書寫,這種錯誤的理解還可能會導致出現下面這樣的錯誤:

RUN cd /App
RUN echo "hello" > world.txt

如果將這個 Dockerfile 進行構建鏡像運行后,會發現找不到 /app/world.txt 文件,或者其內容不是 hello。原因其實很簡單,在 Shell 中,連續兩行是同一個進程執行環境,因此前一個命令修改的內存狀態,會直接影響后一個命令;而在 Dockerfile 中,這兩行 RUN 命令的執行環境根本不同,是兩個完全不同的容器。這就是對 Dockerfile 構建分層存儲的概念不了解所導致的錯誤。

之前說過每一個 RUN 都是啟動一個容器、執行命令、然后提交存儲層文件變更。第一層 RUN cd /app 的執行僅僅是當前進程的工作目錄變更,一個內存上的變化而已,其結果不會造成任何文件變更。而到第二層的時候,啟動的是一個全新的容器,跟第一層的容器更完全沒關系,自然不可能繼承前一層構建過程中的內存變化。

因此,如果需要改變以后各層的工作目錄的位置,那么應該使用 WORKDIR 指令。

它的格式為 WORKDIR <工作目錄路徑>。

12、USER

USER 指令和 WORKDIR 相似,都是改變環境狀態并影響以后的層。WORKDIR 是改變工作目錄,USER 則是改變之后層的執行 RUN、CMD 以及 ENTRYPOINT 這類命令的身份。

當然,和 WORKDIR 一樣,USER 只是幫助你切換到指定用戶而已,這個用戶必須是事先建立好的,否則無法切換。

RUN groupadd -r redis && useradd -r -g redis redis
USER redis
RUN [ "redis-server" ]

如果以 root 執行的腳本,在執行期間希望改變身份,比如希望以某個已經建立好的用戶來運行某個服務進程,不要使用 su 或者 sudo,這些都需要比較麻煩的配置,而且在 TTY 缺失的環境下經常出錯。建議使用 gosu。

# 建立 redis 用戶,并使用 gosu 換另一個用戶執行命令
RUN groupadd -r redis && useradd -r -g redis redis
# 下載 gosu
RUN wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/1.7/gosu-amd64" 
    && chmod +x /usr/local/bin/gosu 
    && gosu nobody true
# 設置 CMD,并以另外的用戶執行
CMD [ "exec", "gosu", "redis", "redis-server" ]

它的使用格式為:

格式:USER <用戶名>[:<用戶組>]

13、HEALTHCHECK

HEALTHCHECK 指令是告訴 Docker 應該如何進行判斷容器的狀態是否正常,這是 Docker 1.12 引入的新指令。

在沒有 HEALTHCHECK 指令前,Docker 引擎只可以通過容器內主進程是否退出來判斷容器是否狀態異常。很多情況下這沒問題,但是如果程序進入死鎖狀態,或者死循環狀態,應用進程并不退出,但是該容器已經無法提供服務了。在 1.12 以前,Docker 不會檢測到容器的這種狀態,從而不會重新調度,導致可能會有部分容器已經無法提供服務了卻還在接受用戶請求。而自 1.12 之后,Docker 提供了 HEALTHCHECK 指令,通過該指令指定一行命令,用這行命令來判斷容器主進程的服務狀態是否還正常,從而比較真實的反應容器實際狀態。

當在一個鏡像指定了 HEALTHCHECK 指令后,用其啟動容器,初始狀態會為 starting,在 HEALTHCHECK 指令檢查成功后變為 healthy,如果連續一定次數失敗,則會變為 unhealthy。

HEALTHCHECK 支持下列選項:

  • --interval=<間隔>:兩次健康檢查的間隔,默認為 30 秒;
  • --timeout=<時長>:健康檢查命令運行超時時間,如果超過這個時間,本次健康檢查就被視為失敗,默認 30 秒;
  • --retries=<次數>:當連續失敗指定次數后,則將容器狀態視為 unhealthy,默認 3 次。

和 CMD, ENTRYPOINT 一樣,HEALTHCHECK 只可以出現一次,如果寫了多個,只有最后一個生效。

它的使用格式為:

  • HEALTHCHECK [選項] CMD <命令>:設置檢查容器健康狀況的命令
  • HEALTHCHECK NONE:如果基礎鏡像有健康檢查指令,使用這行可以屏蔽掉其健康檢查指令

假設我們有個鏡像是個最簡單的 Web 服務,我們希望增加健康檢查來判斷其 Web 服務是否在正常工作,我們可以用 curl 來幫助判斷,其 Dockerfile 的 HEALTHCHECK 可以這么寫:

FROM Nginx
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
HEALTHCHECK --interval=5s --timeout=3s 
  CMD curl -fs http://localhost/ || exit 1

這里我們設置了每 5 秒檢查一次(這里為了試驗所以間隔非常短,實際應該相對較長),如果健康檢查命令超過 3 秒沒響應就視為失敗,并且使用 curl -fs http://localhost/ || exit 1 作為健康檢查命令。

14、ONBUILD

ONBUILD 是一個特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而這些指令,在當前鏡像構建時并不會被執行。只有當以當前鏡像為基礎鏡像,去構建下一級鏡像的時候才會被執行。

Dockerfile 中的其它指令都是為了定制當前鏡像而準備的,唯有 ONBUILD 是為了幫助別人定制自己而準備的。

好了,命令介紹完了,下面以使用Dockerfile構建lnmp容器的過程,我們再來具體介紹下Dockerfile吧。

如下是Dockerfile的構建目錄,這里我們先提前下載好了源碼包:

dockerfile/
├── nginx
│   ├── Dockerfile
│   ├── nginx-1.12.1.tar.gz
│   └── nginx.conf
└── php
    ├── Dockerfile
    ├── php-5.6.31.tar.gz
    └── php.ini

nginx、php里面分別存放Dockerfile文件、源碼包。nginx目錄下還放了nginx.conf配置文件,php目錄下也放置了php.ini配置文件。

有些人可能會問為什么要把nginx.conf、php.ini配置文件放到這里,有兩個原因,其一,把這兩個默認的配置文件放在這里可以提前修改好所需要的參數,當容器啟動后,就不需要在進入容器去修改了。當然,我這里只是練習環境,并未對這兩個文件做任何更改。其二,在實際環境中,這兩個文件是經常需要修改的,單獨拿出來后在啟動容器時你可以把這兩個文件mount到容器中,便于管理。

一、Nginx構建

FROM centos:7 // 以 centos:7 鏡像為基礎鏡像
MAINTAINER yuanma // 指定鏡像制作者
ENV TIME_ZOME Asia/Shanghai // 設置時區環境變量

RUN yum -y install gcc gcc-c++ make openssl-devel pcre-devel // 使用 RUN 命令下載編譯相關工具,為后面的編譯做準備
ADD nginx-1.12.1.tar.gz /tmp // ADD 可以自動解壓文件,并將解壓后的文件 COPY 到指定目錄

RUN cd /tmp/nginx-1.12.1 && 
        ./configure --prefix=/usr/local/nginx && 
        make && 
        make install // 進入到 nginx 臨時安裝目錄,然后執行編譯安裝

RUN rm -rf /tmp/nginx* && yum clean all && 
        echo "${TIME_ZOME}" > /etc/timezone && 
        ln -sf /usr/share/zoneinfo/${TIME_ZOME} /etc/localtime // 刪除編譯安裝期間產生的臨時文件,同時記錄時區

COPY nginx.conf /usr/local/nginx/conf/ # 轉移構建目錄中的配置文件到 nginx 配置文件所在目錄,以達到修改 nginx 配置文件的目的
WORKDIR /usr/local/nginx/ # 指定工作目錄,以后每一層的當前目錄都是此目錄
EXPOSE 80 // 說明將對外暴露80端口,但這不代表會自動映射80端口到宿主機
CMD ["./sbin/nginx","-g","daemon off;"] // 指定容器啟動后,在容器中執行的命令,這里表示容器啟動后,就啟動nginx。

構建鏡像

docker build -t  nginx:demo(鏡像名稱)

2、PHP構建

FROM centos:7 // 以 centos:7 鏡像為基礎鏡像
MAINTAINER yuanma // 指定鏡像制作者
ENV TIME_ZOME Asia/Shanghai // 設置時區環境變量
RUN yum install -y gcc gcc-c++ make gd-devel libxml2-devel libcurl-devel libjpeg-devel libpng-devel openssl-devel # 使用 RUN 命令下載編譯相關工具,為后面的編譯做準備
ADD php-5.6.31.tar.gz /tmp/ // ADD 可以自動解壓文件,并將解壓后的文件 COPY 到指定目錄

RUN cd /tmp/php-5.6.31 && 
        ./configure --prefix=/usr/local/php 
        --with-config-file-path=/usr/local/php/etc 
        --with-MySQL --with-mysqli 
        --with-openssl --with-zlib --with-curl --with-gd 
        --with-jpeg-dir --with-png-dir --with-iconv 
        --enable-fpm --enable-zip --enable-mbstring && 
        make -j 4 && 
        make install // 進入到 php 臨時安裝目錄,然后執行編譯安裝

RUN cp /usr/local/php/etc/php-fpm.conf.default /usr/local/php/etc/php-fpm.conf && 
        sed -i 's/127.0.0.1/0.0.0.0/g' /usr/local/php/etc/php-fpm.conf && 
        sed -i "21a daemonize=no" /usr/local/php/etc/php-fpm.conf && 
        echo "${TIME_ZOME}" > /etc/timezone && 
        ln -sf /usr/share/zoneinfo/${TIME_ZOME} /etc/localtime // 修改 php-fpm 配置文件

COPY php.ini /usr/local/php/etc/ //  轉移構建目錄中的配置文件到 PHP 配置文件所在目錄,以達到修改 PHP 配置文件的目的
RUN rm -rf /tmp/php* && yum clean all // 同時刪除安裝 PHP 時產生的一些臨時文件
WORKDIR /usr/local/php/ // 指定工作目錄,以后每一層的當前目錄都是此目錄
EXPOSE 9000 // 說明將對外暴露9000端口,但這不代表會自動映射9000端口到宿主機
CMD ["./sbin/php-fpm","-c","/usr/local/php/etc/php-fpm.conf"] // 指定容器啟動后,在容器中執行的命令,這里表示容器啟動后,就啟動php-fpm。

構建鏡像

docker build -t  php:demo(鏡像名稱)

3、MySQL構建

FROM centos:7 # 以 centos:7 鏡像為基礎鏡像
MAINTAINER yuanma # 指定鏡像制作者
ENV TIME_ZOME Asia/Shanghai # 設置時區環境變量
RUN yum install mysql mysql-server
RUN /etc/init.d/mysqld start &&
mysql -e "grant all privileges on *.* to 'root'@'%' identified by 'abc123';" &&
mysql -e "grant all privileges on *.* to 'root'@'localhost' identified by 'abc123';"      //root在本地,非本地登錄時都使用abc123密碼
EXPOSE 3306
CMD ["mysqld_safe"]

構建鏡像

docker build -t  mysql:demo(鏡像名稱)

4、運行容器

首先創建自定義網絡lnmp,然后運行ningx、php這些容器的時候加入到lnmp網絡中來

# docker network  create  lnmp

創建php容器

docker run -itd --name lnmp_php --network lnmp --mount type=bind,src=/app/wwwroot,dst=/usr/local/nginx/html php:demo

參數說明:
-itd:   在容器中打開一個偽終端進行交互操作,并在后臺運行;
--name: 為容器分配一個名字lnmp_php;
--network:為容器指定一個網絡環境為lnmp網絡;
--mout: 把宿主機的/app/wwwroot目錄掛載到容器的/usr/local/nginx/html目錄,掛載也相當于數據持久化;
php:demo:指定剛才構建的php鏡像來啟動容器;

創建nginx容器

# docker run -itd --name lnmp_nginx --network lnmp -p 80:80 --mount type=bind,src=/app/wwwroot,dst=/usr/local/nginx/html nginx:demo

創建mysql容器

# docker volume  create  mysql-volume
docker run -itd  --name lnmp_mysql --network lnmp -p 3306:3306 --mount src=mysql-volume,dst=/var/lib/mysql -e MYSQL_ROOT_PASSword=123456 mysql --character-set-server=utf8

至此,使用 dockerfile 構建 Docker 容器就完成了

分享到:
標簽:架構
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定