前面幾篇文章已經給你們介紹了 Docker 的基本概念,相信你們也會使用 Docker 運行本身想要的容器了。可是隻有學會製做鏡像,才能將 Docker 應用到咱們的項目中去。下面咱們就來學習如何使用 Dockerfile 來製做鏡像。html
Dockerfile 是一個文本文件,裏面的內容是一條條的指令,每一條指令將會構建一層,所以每條指令的內容就是在描述該層應當如何建立。前端
接下來以 nginx 鏡像爲例,定製一個簡單的鏡像,首先建立一個目錄 mynginx,進入目錄再建立一個文本文件,名字爲 Dockerfile。python
$ mkdir mynginx
$ cd mynginx
$ touch Dockerfile
複製代碼
把如下內容寫到 Dockerfile 中nginx
FROM nginx
RUN echo '<h1>Hello, Docker!<h1>' > /usr/share/nginx/html/index.html 複製代碼
其中 FROM
用來指定基礎鏡像,上面的例子是以 nginx 爲基礎鏡像。git
RUN
命令則表示執行一個 shell 命令,將文本寫進 index.html
。github
編寫完 Dockerfile 以後就能夠用來構建鏡像。構建 docker 鏡像的命令以下:redis
$ docker build [OPTIONS] PATH | URL | -
複製代碼
選項的說明以下:docker
OPTIONS | 說明 |
---|---|
--build-arg=[] | 設置鏡像建立時的變量 |
--cpu-shares | 設置 CPU 使用權重 |
--cpu-period | 限制 CPU CFS 週期 |
--cpu-quota | 限制 CPU CFS 配額 |
--cpuset-cpus | 指定使用的 CPU |
--cpuset-mems | 指定使用的內存 id |
--disable-content-trust | 忽略檢驗,默認開啓 |
-f | 指定要使用的 Dockerfile 路徑 |
--force-rm | 設置鏡像過程當中刪除中間容器 |
--isolation | 使用容器隔離技術 |
--label=[] | 設置鏡像使用的元數據 |
-m | 設置內存最大最 |
--memory-swap | 設置 Swap 的最大值爲內存 + swap,'-1' 表示不限 swap |
--no-cache | 建立鏡像的過程當中不適用緩存 |
--pull | 嘗試更新鏡像的新版本 |
--quiet,-q | 安靜模式,成功後只輸出鏡像 ID |
--rm | 設置鏡像成功後刪除中間容器 |
--shm-size | 設置 /dev/shm 的大小,默認值是 64M |
--ulimit | Ulimit 配置 |
--tag,-t | 鏡像的名字及標籤,一般 name:tag 或者 name 格式,能夠在一次構建中爲一個鏡像設置多個標籤 |
--network | 默認 default。在構建期間設置 RUN 指令的網絡模式 |
下面舉幾個例子,說明選項的用法shell
fedevelop/example:v1
$ docker build -t fedevelop/example:v1 .
複製代碼
$ docker build github.com/ad-feiben/qc-remind
複製代碼
$ docker build -f /path/to/a/Dockerfile .
複製代碼
回到 mynginx
目錄中執行下面的命令數組
$ docker build -t nginx:v2 .
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM nginx
---> f949e7d76d63
Step 2/2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
---> Running in 88dc64292fa7
Removing intermediate container 88dc64292fa7
---> 5d1e253d361c
Successfully built 5d1e253d361c
Successfully tagged nginx:v2
複製代碼
注意不要漏了最後的 .
,.
表明將當前目錄設置爲鏡像構建上下文(Context)。
例如 Dockerfile 的內容以下:
COPY ./requirements.txt /app/ 複製代碼
意思爲複製上下文目錄下的 requirements.txt
,與 Dockerfile、執行 docker build
所在的目錄無關。
構建完成後,咱們能夠經過 Docker images
查看咱們構建的鏡像
$ docker images
docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx v2 5d1e253d361c About a minute ago 126MB
nginx latest f949e7d76d63 4 weeks ago 126MB
複製代碼
接下來用咱們定製的鏡像來啓動一個容器看看,其中 5d1e253d361c
替換爲你的鏡像 id
$ docker run -it -p 80:80 5d1e253d361c
複製代碼
瀏覽器打開 http://localhost/ 能夠看到頁面顯示的是 Hello, Docker!
,說明咱們的 Dockerfile 中的命令生效了。
FROM 指定基礎鏡像
FROM
是用來指定基礎鏡像,這個命令是 Dockerfile 中必備的指令,而且必須是第一條指令。
假如不須要基礎鏡像,可使用空白鏡像 scratch
做爲基礎鏡像。scratch
這個鏡像是虛擬的,實際並不存在。
FROM scratch
...
複製代碼
RUN 執行命令
從上面的例子中能夠看到 RUN
能夠執行一個 shell
命令,除了此以外還有另外一種格式。
exec
格式:RUN ["可執行文件", "參數"]
。
咱們在編寫 Dockerfile 的時候須要儘量將指令連接起來,由於 Dockerfile 中的每一條指令都會創建一層,若是創建太多層,不只會使得鏡像很是臃腫,也會增長構建時間。
# 錯誤示範
FROM debian:stretch
RUN apt-get update
RUN apt-get install -y gcc libc6-dev make wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install
複製代碼
正確的寫法以下,使用 &&
將多條命令合併爲一條,而且刪除沒必要要的文件、清理 apt
緩存等,儘可能保持容器乾淨。若是沒有作清理工做的話,這些冗餘的文件等將會帶到下一層,而且會一直跟隨鏡像。
FROM debian:stretch
RUN buildDeps='gcc libc6-dev make wget' \
&& apt-get update \
&& apt-get install -y $buildDeps \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& mkdir -p /usr/src/redis \
&& tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
&& make -C /usr/src/redis \
&& make -C /usr/src/redis install \
&& rm -rf /var/lib/apt/lists/* \
&& rm redis.tar.gz \
&& rm -r /usr/src/redis \
&& apt-get purge -y --auto-remove $buildDeps
複製代碼
WORKDIR 指定工做目錄
WORKDIR
的格式爲 WORKDIR <工做目錄路徑>
當使用 WORKDIR
指定工做路徑後,之後的每一層的當前目錄都會被改成工做目錄,若是目錄不存在,WORKDIR
會幫助咱們建立目錄。
若是須要改變之後各層的工做目錄的位置,只須要再使用 WORKDIR 指令便可。
COPY 複製文件
COPY
的格式爲 COPY [--chown=<user>:<group>] <源路徑>... <目標路徑>
源路徑
能夠是多個,也可使用通配符,例以下面這樣:
COPY hom* /mydir/ COPY hom?.txt /mydir/ 複製代碼
目標路徑
能夠是容器內的絕對路徑,也能夠相對工做目錄的相對路徑。目標路徑不須要咱們建立,若是目標路徑不存在會在複製文件前先行建立缺失的目錄。
使用 COPY
複製文件時,會保留文件的元數據,好比讀寫權限,文件變動的時間等。若是須要修改文件的所屬用戶及所屬組,能夠經過添加 --chown=<user>:<group>
選項進行修改。
CMD 容器啓動命令
shell 格式爲 CMD <命令>
exec 格式爲 CND ["可執行文件", "參數1", "參數2"]
使用 shell 格式的話,實際的命令會被包裝成 sh -c
的形式進行執行,好比:
CMD echo $HOME
在實際執行中,將會變成 CMD [ "sh", "-c", "echo $HOME" ]
因此在使用 CMD
的時候通常推薦使用 exec
的格式,須要注意的是 exec
的格式會被解析成 JSON
數組,因此只可以使用雙引號,而不能使用單引號。
Dockerfile 的指令不止這麼幾個,感興趣的小夥伴能夠到 yeasy.gitbooks.io/docker_prac… 自行查看。
下面將經過個人 Python 項目來演示,怎麼編寫一個 Dockerfile,文件地址在 raw.githubusercontent.com/AD-feiben/q…
文件的內容以下:
# 指定基礎鏡像
FROM python:3.7.4
# 設置鏡像做者
MAINTAINER feiben <feiben.dev@gmail.com>
# 設置工做目錄
WORKDIR /app
# 複製上下文的文件到容器的 app 目錄下
# 不須要複製到鏡像的文件可使用 .dockerignore 進行忽略
COPY . /app
# 執行下面命令,同步時區,安裝依賴
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo 'Asia/Shanghai' >/etc/timezone \ && pip install -r requirements.txt
# 啓動容器
CMD ["python", "main.py", "--log-file-prefix", "qc-remind.log"] 複製代碼
當咱們的代碼編寫完成後,就能夠執行 docker build -t <name>:<tag> .
將代碼打包成一個 Docker 鏡像,再 push 到鏡像倉庫中。
按照傳統的方式部署項目,一般須要在服務器安裝一套運行環境,並且經常會遇到環境不一致致使本地開發沒問題,一到線上部署就出現各類問題的狀況。而且一旦服務器到期,遷移的工做量也是十分巨大。
而使用 Docker,咱們只須要再服務器安裝一個 Docker 環境便可,部署項目只須要執行 docker run xxx
。不只減小了安裝環境的時間,也保證了環境的一致性。
若是你喜歡個人文章,但願能夠關注一下個人公衆號【前端develop】