摘要:正確的做法是直接執行可執行文件,并且要求以前臺形式運行。官方鏡像官方鏡像在這里先定義了環境變量,其后的這層里,多次使用來進行操作定制。只有當以當前鏡像為基礎鏡像,去構建下一級鏡像的時候才會被執行。
基礎命令
名稱 | 作用 | 示例 |
---|---|---|
docker systen df | 查看鏡像、容器、數據卷所占的空間 | |
docker images -q | 產生指定范圍的id列表 | docker image ls -q redis |
docker image rm $() | 批量刪除指定鏡像 | docker image rm $(docker image ls -q redis) |
docker run | 基于鏡像啟動容器 | docker run --name webserver -d -p 80:80 nginx |
docker exec | 進入容器 | docker exec -it webserver /bin/bash |
docker diff | 查看容器存儲層的改動 | docker diff webserver |
docker commit | 將容器的存儲層保存為鏡像 | docker commit [選項] <容器ID或容器名> [<倉庫名>[:<標簽>]] |
docker history | 具體查看鏡像歷史 | docker history nginx:v2 |
docker export | 導出本地容器 | docker export c422162c86da >mysql.tar |
docker import | 導入容器快照到本地鏡像倉庫 | cat mysql.tar | docker import - test/mysql:v1.0 |
docker save | 保存鏡像(推薦Docker Registry方式) | docker save docker.io/mysql | gzip > mysql-test.tar.gz |
docker load | 加載鏡像(推薦Docker Registry方式) | docker load -i mysql-test.tar.gz |
名稱 | 作用 | 示例 |
---|---|---|
FROM | 指定基礎鏡像 | FROM scratch 指定一個空白的鏡像 |
RUN | 用來執行命令行命令的 | RUN ["可執行文件", "參數1", "參數2"] |
COPY | 從構建上下文目錄中 <源路徑> 的文件/目錄復制到新的一層的鏡像內的 <目標路徑> 位置 | COPY <源路徑>... <目標路徑> |
ADD | 更高級的復制文件 | (幾乎不用它)所有復制文件用COPY,僅在需要自動解壓縮的場合使用 ADD |
CMD | 容器啟動命令 | 推薦使用 exec 格式 CMD ["可執行文件", "參數1", "參數2"...] 注意是雙引號 |
ENTRYPOINT | 入口點 | 1 讓鏡像變成像命令一樣使用; 2 應用運行前的準備工作 |
ENV | 設置環境變量 | ENV |
ARG | 構建參數 | ARG <參數名>[=<默認值>] |
VOLUME | 定義匿名卷 | VOLUME ["<路徑1>", "<路徑2>"...] |
EXPOSE | 聲明運行時容器提供服務端口 | EXPOSE <端口1> [<端口2>...] |
WORKDIR | 指定工作目錄 | WORKDIR <工作目錄路徑> |
USER | 指定當前用戶 | USER <用戶名> |
HEALTHCHECK | 健康檢查 | HEALTHCHECK [選項] CMD <命令> :設置檢查容器健康狀況的命令 |
ONBUILD | 為他人做嫁衣 | ONBUILD <其它指令> |
介紹
Dockerfile 是一個文本文件,里面包含了一條條的指令,每一條指令構建一層,因此每一條指令的內容都是描述該層如何構建。
使用dockerfile的好處
避免了docker commit方式帶來的臃腫,實際應用中不應采用docker commit.
基本流程
mkdir mynginx cd mynginx touch Dockerfile vim Dockerfile,寫入 FROM nginx RUN echo "正確構建Hello, Docker!
" > /usr/share/nginx/html/index.html 構建鏡像 docker build -t nginx:v3 . # 注意最后面有一個點 or docker build - < Dockerfile #從標準輸入中讀取 Dockerfile 進行構建 or cat Dockerfile | docker build - or docker build http://server/context.tar.gz #用給定的 tar 壓縮包構建 or docker build https://github.com/twang2218/gitlab-ce-zh.git#:8.14 # 直接用 Git repo 進行構建 or docker build - < context.tar.gz # 從標準輸入中讀取上下文壓縮包進行構建
Dockerfile 中每一個指令都會建立一層, RUN 也不例外。每一個 RUN 的行為, 就和剛才我們手工建立鏡像的過程一樣:新建立一層,在其上執行這些命令,執行結束 后, commit 這一層的修改,構成新的鏡像。錯誤的示例
FROM debian:jessie RUN apt-get update RUN apt-get install -y gcc libc6-dev make RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.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正確的寫法
FROM debian:jessie RUN buildDeps="gcc libc6-dev make" && apt-get update && apt-get install -y $buildDeps && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.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關于上下文
COPY ./package.json /app/ 這并不是要復制執行 docker build 命令所在的目錄下的 package.json ,也不是復制 Dockerfile 所在目錄下的 package.json ,而是復制 上下文(context) 目錄下的 package.jsonADD
FROM scratch ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz / ...CMD
shell格式: CMD echo $HOME 實際執行: CMD [ "sh", "-c", "echo $HOME" ] Docker 不是虛擬機,容器中的應用都應該以前臺執行,而不是像虛擬機、物理機里面那樣, 用 upstart/systemd 去啟動后臺服務,容器內沒有后臺服務的概念。 CMD service nginx start 這個命令會被理解為 CMD [ "sh", "-c", "service nginx start"] ,因此主進程實際上是 sh 。 那么當 service nginx start 命令結束后, sh 也就結束了, sh 作為主進程退出了,自然就會令容器退出。 正確的做法是直接執行 nginx 可執行文件,并且要求以前臺形式運行。比如: CMD ["nginx", "-g", "daemon off;"]ENTRYPOINT
場景一:讓鏡像變成像命令一樣使用
錯誤的示范
FROM ubuntu:16.04 RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* CMD [ "curl", "-s", "http://ip.cn" ] docker build -t myip . docker run myip docker run myip -i # 如果加上-i參數,就會報錯
正確的示范
FROM ubuntu:16.04 RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]
場景二:應用運行前的準備工作
啟動容器就是啟動主進程,但有些時候,啟動主進程前,需要一些準備工作。 官方redis鏡像 FROM alpine:3.4 ... RUN addgroup -S redis && adduser -S -G redis redis ... ENTRYPOINT ["docker-entrypoint.sh"] EXPOSE 6379 CMD [ "redis-server" ]
docker-entrypoint.sh #!/bin/sh ... # allow the container to be started with `--user` if [ "$1" = "redis-server" -a "$(id -u)" = "0" ]; then chown -R redis . exec su-exec redis "$0" "$@" fi exec "$@"ENV
官方node鏡像 ENV NODE_VERSION 7.2.0 RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.ta r.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 在這里先定義了環境變量 NODE_VERSION ,其后的 RUN 這層里,多次使用 $NODE_VERSION 來進行操作定制。 可以看到,將來升級鏡像構建版本的時候,只需要更新 7.2.0 即可, Dockerfile 構建維護變得更輕松了。 下列指令可以支持環境變量展開: ADD 、 COPY 、 ENV 、 EXPOSE 、 LABEL 、 USER 、 WORKDIR 、 VOLUME 、 STOPSIGNAL 、 ONBUILD 。ARG
Dockerfile 中的 ARG 指令是定義參數名稱,以及定義其默認值。該默認值可以在構建命令 docker build 中用 --build-arg <參數名>=<值> 來覆蓋。VOLUME
VOLUME /data 這里的 /data 目錄就會在運行時自動掛載為匿名卷,任何向 /data 中寫入的信息都不會記錄進容器存儲層, 從而保證了容器存儲層的無狀態化。當然,運行時可以覆蓋這個掛載設置。 docker run -d -v mydata:/data xxxx 在這行命令中,就使用了 mydata 這個命名卷掛載到了 /data 這個位置,替代了Dockerfile 中定義的匿名卷的掛載配置。EXPOSE
要將 EXPOSE 和在運行時使用 -p <宿主端口>:<容器端口> 區分開來。 -p ,是映射宿主端口和 容器端口,換句話說,就是將容器的對應端口服務公開給外界訪問,而 EXPOSE 僅僅是聲明 容器打算使用什么端口而已,并不會自動在宿主進行端口映射WORKDIR
錯誤的示例
初學者常犯的錯誤是把 Dockerfile 等同于 Shell 腳本來書寫 RUN cd /app RUN echo "hello" > world.txt 如果需要改變以后各層的工作目錄的位置,那么應該使用 WORKDIR 指令USER
USER 指令和 WORKDIR 相似,都是改變環境狀態并影響以后的層,用戶需提前建好. RUN groupadd -r redis && useradd -r -g redis redis USER redis RUN [ "redis-server" ]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 作為健康檢查命令。 查看 docker inspect --format "{{json .State.Health}}" web | python -m json.toolONBUILD
ONBUILD 是一個特殊的指令,它后面跟的是其它指令,比如 RUN , COPY 等,而這些指令, 在當前鏡像構建時并不會被執行。只有當以當前鏡像為基礎鏡像,去構建下一級鏡像的時候才會被執行。 Dockerfile 中的其它指令都是為了定制當前鏡像而準備的,唯有 ONBUILD 是為了幫助別人定制自己而準備的。
假設一個node.js的dockerfile如下
FROM node:slim RUN mkdir /app WORKDIR /app COPY ./package.json /app RUN [ "npm", "install" ] COPY . /app/ CMD [ "npm", "start" ]
現在有其他的鏡像依賴這個鏡像,假設基礎鏡像叫my-node
FROM node:slim RUN mkdir /app WORKDIR /app CMD [ "npm", "start" ]
那么其他依賴的子項目的鏡像為
FROM my-node COPY ./package.json /app RUN [ "npm", "install" ] COPY . /app/ 基礎鏡像變化后,各個項目都用這個 Dockerfile 重新構建鏡像,會繼承基礎鏡像的更新 但是問題只解決了一半,如果這個子Dockerfile 里面有些東西需要調整呢? 比如 npm install 都需要加一些參數,那怎么辦?這一行 RUN 是不可能放入基礎鏡像的, 因為涉及到了當前項目的 ./package.json ,難道又要一個個修改么? 所以說,這樣制作基礎鏡像,只解決了原來的 Dockerfile 的前4條指令的變化問題, 而后面三條指令的變化則完全沒辦法處理。
用ONBUILD重寫基礎鏡像
FROM node:slim RUN mkdir /app WORKDIR /app ONBUILD COPY ./package.json /app ONBUILD RUN [ "npm", "install" ] ONBUILD COPY . /app/ CMD [ "npm", "start" ] 在用ONBUILD構建基礎鏡像的時候,這三行并不會被執行
那么子鏡像只需
FROM my-node 當在各個項目目錄中,用這個只有一行的 Dockerfile 構建鏡像時,之前基礎鏡像的那三行 ONBUILD 就會開始執行, 成功的將當前項目的代碼復制進鏡像、并且針對本項目執行 npm install ,生成應用鏡像參考文檔
Docker 從入門到實踐
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/27405.html
摘要:導讀要從容器化開始,而容器又需要從開始,本文將介紹如何寫出一個優雅的文件。只要記住以上三點就能寫出不錯的。執行完成項目的構建。 導讀 Kubernetes要從容器化開始,而容器又需要從Dockerfile開始,本文將介紹如何寫出一個優雅的Dockerfile文件。 文章主要內容包括: Docker容器 Dockerfile 使用多階構建 感謝公司提供大量機器資源及時間讓我們可以實踐...
摘要:用于配置當前所創建的鏡像作為其它新創建鏡像的基礎鏡像時,所執行的操作指令。運行構建命令構建命令用于使用創建鏡像。 本文旨在用通俗的語言講述枯燥的知識 前面講到鏡像的構建時,講述的是用commit的方式構建鏡像,而Dockerfile是另一種構建鏡像的方式。 Dockerfile構建鏡像是以基礎鏡像為基礎的,Dockerfile是一個文本文件,內容是用戶編寫的一些docker指令,每一條...
摘要:我們可以了解到,鏡像的定制實際上就是定制每一層所添加的配置文件。指令之指令的目的就是來指定基礎鏡像。指令之指令是用來執行命令行命令的。由于命令行的強大能力,指令在定制鏡像時是最常用的指令之一。構建鏡像這里我們使用了命令進行鏡像構建。 我們可以了解到,鏡像的定制實際上就是定制每一層所添加的配置、文件。如果我們可以把每一層修改、安裝、構建、操作的命令都寫入一個腳本,用這個腳本來構建、定制鏡...
摘要:本文已獲得原作者授權。在構建鏡像的過程中會緩存一系列中間鏡像。鏡像時,會順序執行中的指令,并同時比較當前指令和其基礎鏡像的所有子鏡像,若發現有一個子鏡像也是由相同的指令生成,則命中緩存,同時可以直接使用該子鏡像而避免再去重新生成了。 本文已獲得原作者 CodeSheep 授權。 概述 Dockerfile 是專門用來進行自動化構建鏡像的編排文件(就像 Jenkins 2.0時代的 J...
摘要:前言自動化構建是應用發布過程中必不可少的環節,常用的構建工具有等。當然,我推薦個人體驗的話就用官方的吧,因為這樣你構建的鏡像還可以與他人共享。 前言 自動化構建是應用發布過程中必不可少的環節, 常用的構建工具有jenkins ,walle 等。而這些工具在構建應用時通常會有以下問題: 需要直接或間接的寫一坨用于構建的shell命令等,不易管理、兼容性較差 上面一點可能還比較容易解決,...
摘要:但是看了下,里面的軟件源還是官方的,而且沒有安裝,所以就打算自己寫一個,用它來構建適合自己的基礎鏡像。我事先配置好的,都是些基礎的配置。添加的文件必須以構建上下文為根目錄來找,不能超出構建上下文的范圍。 我們可以從Docker Hub上下載官方倉庫中的鏡像,我自己就下載了ubuntu鏡像,只有188M左右,很小巧了。但是看了下,里面的軟件源還是官方的,而且沒有安裝vim,所以就打...
閱讀 3303·2021-11-24 09:39
閱讀 2815·2021-10-12 10:20
閱讀 1917·2019-08-30 15:53
閱讀 3082·2019-08-30 14:14
閱讀 2611·2019-08-29 15:36
閱讀 1129·2019-08-29 14:11
閱讀 1961·2019-08-26 13:51
閱讀 3415·2019-08-26 13:23