鏡像制作
說明:
Docker 鏡像中有沒有內核
- 鏡像本身很小,最小只有幾M,當鏡像作為容器啟動后,直接使用物理機的內核,而鏡像本身只提供rootfs(保證系統基本運行的文件系統:/dev、proc、/bin、/etc等,容器中boot目錄為空)
- 由於沒有內核,不會直接調用物理硬件,所以也不會涉及到硬件驅動,因此也無需容器內擁有自已的內核和驅動。而如果使用虛擬機技術,對應每個虛擬機都有自已獨立的內核
容器中必須啟動前台運行的程序:
- 容器如果希望啟動后能持續運行,就必須有一個能前台持續運行的進程,如果在容器中啟動傳統的服務,如:httpd,php-fpm等均為后台進程模式運行,就導致docker在前台沒有運行的應用,這樣的容器啟動后會立即退出。所以一般會將服務程序以前台方式運行,對於有一些可能不知道怎么實現前台運行的程序,只需要在你啟動的該程序之后添加類似於tail、top這種可以前台運行的程序即可.比較常用的方法,如 tail -f /etc/hosts
例:
httpd
ENTRYPOINT [ "/usr/sbin/apache2" ]
CMD ["-D", "FOREGROUND"]
nginx
ENTRYPOINT [ "/usr/sbin/nginx", "-g", "daemon off;" ]
用腳本運行容器,不能前台執行的程序,就手動創造一個前台
cat run_haproxy.sh
#!/bin/bash
haproxy -f /etc/haproxy/haproxy.cfg
tail -f /etc/hosts
tail -n1 Dockerfile
CMD ["run_haproxy.sh"]
鏡像制作方法:
鏡像制作類似於虛擬機的鏡像(模版)制作,即按照公司的實際業務需求將需要安裝的軟件、相關配置等基礎環境配置完成,然后將其做成鏡像,最后再批量從鏡像批量生成容器實例,這樣可以極大的簡化相同環境的部署工作
第一種:基於原有容器做修改(手動制作)
- 用網上已有的基礎鏡像,運行一個容器后,在這個容器里面做修改,修改完成后制作成新鏡像,最后推的鏡像倉庫
- docker commit 通過修改現有容器,將之手動構建為鏡像
第二種:寫腳本構建新的鏡像(自動制作,企業常用)
- 編寫構建鏡像的dokcerfile文件(類似腳本),構建完成后可以運行容器或推到鏡像倉庫
- docker build 通過Dockerfile文件,批量構建為鏡像
手動構建鏡像:
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
選項:
-a string 鏡像作者信息
-c 指令 添加一些dockerfile的指令
-m string 提交信息,一般記錄有哪些修改
-p 提交鏡像的時候,暫停容器,默認是暫停
說明:
- 制作鏡像和容器狀態無關,停止狀態也可以制作鏡像
- 如果沒有指定[鏡像名[:版本]],REPOSITORY和TAG都為<none>
- 提交的時候標記TAG號:
- 生產當中常用,后期可以根據TAG標記創建不同版本的鏡像以及創建不同版本的容器
構建鏡像大致步驟:
- 下載一個系統的官方基礎鏡像,如: CentOS 或 Ubuntu
- 基於基礎鏡像啟動一個容器,並進入到容器
- 在容器里面做配置操作
- 安裝基礎命令
- 配置運行環境
- 安裝服務和配置服務
- 放業務程序代碼
- 提交為一個新鏡像 docker commit
- 基於自己的的鏡像創建容器並測試訪問
基於busybox制作httpd鏡像
bosybox自帶一個httpd程序,可直接運行web
httpd -h
-i
-f 不以守護經常運行
-v[v] 顯示訪問日志
-p [ip:]端口 設置監聽端口
-u user[:組] 程序運行身份
-r 開啟basic認證
-h 目錄 指定家目錄,默認當前目錄
-c 文件 配置文件路徑,默認{/etc、home}/httpd.conf
-m string md5加密
-e string html
-d url
1)准備基礎鏡像並運行容器
docker run -it --name b1 busybox
mkdir -p /data/html
echo 'test website' > /data/html/index.html
2)制作v1版httpd
#-a說明作者,-c在容器運行時,執行httpd命令設置家目錄並前台執行,暴露80端口,基於b1容器,制作成httpd-busybox:v1.0
docker commit -a "hj" -c 'CMD /bin/httpd -fv -h /data/html' -c "EXPOSE 80" b1 httpd-busybox:v1.0
3)制作v2版httpd
#制作時未暴露端口,運行時要-p,-P不能成功(因為必須在制作時指定暴露端口才能使用-P)
docker commit -a "hj" b1 httpd-busybox:v2.0
制作tomcat
1)運行官方tomcat
docker run -td --name t1 -p 8080:8080 tomcat
docker exec -it t1 bash
cp -a webapps.dist/* webapps/
exit
2)制作v1版
docker commit -m "hj's web app" -a 'www.hj.com' t1 hj-tomcat:v1.0
docker images
docker run -td --name hj-t1 -p 81:8080 hj-tomcat:v1.0
curl 2.2.2.42:81
基於Ubuntu制作nginx
1)運行Ubuntu並換源
docker run -it -p 80 -p 443 --name ngx_ub ubuntu
#由於docker安裝的系統,都沒有設置時區,所有系統都要設置時區
echo 'TZ="Asia/Shanghai"; export TZ' >> /etc/profile
. /etc/profile
或者:
rm -rf /etc/localtime
ln -sv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
2)nginx設置
docker exec -it ngx_ub bash
sed -i.bak 's@:.*/@://mirrors.aliyun.com/ubuntu/@g' /etc/apt/sources.list
apt update
apt install -y nginx 一般安裝完后建議清除apt/yum緩沖,節約空間
#docker安裝的nginx的家目錄在/var/www/html
grep root /etc/nginx/sites-enabled/default
echo Nginx Website in Docker > /var/www/html/index.html
3)制作nginx鏡像,並啟動
docker commit -c "EXPOSE 80 443" ngx_ub hj-nginx:v1
#nginx的-g是設置配置文件,在配置文件中關閉守護進程
docker run -d -p 80 -p 443 --name hj-n1 hj-nginx:v1 nginx -g 'daemon off;'
centos編譯安裝nginx
1)運行centos
docker run -it --name ngx_ct centos bash
cd /etc/yum.repos.d/;rm -rf *
curl -G http://mirrors.aliyun.com/repo/Centos-8.repo > ctos8.repo
2)編譯安裝
docker exec -it ngx_ct bash
cd /opt
yum install -y gcc gcc-c++ pcre-devel zlib-devel openssl-devel vim wget make
wget http://nginx.org/download/nginx-1.20.1.tar.gz
tar xf nginx-1.20.1.tar.gz
cd nginx-1.20.1
./configure --prefix=/opt/nginx
make && make install
cd ..
rm -rf nginx-*
yum clean all
3)配置nginx
cd nginx
sed -i '3 a daemon off;' conf/nginx.conf
echo nginx web > html/index.html
4)制作鏡像
docker commit -m "hj's src nginx" -c "CMD /opt/nginx/sbin/nginx" ngx_ct hj-src-nginx:v1
docker run -d -p 80:80 --name hj-n3 hj-src-nginx:v1
自動構建鏡像:
介紹:
- DockerFile是一種被Docker程序解釋執行的腳本,由一條條的命令組成的,每條命令對應linux下面的一條命令,Docker程序將這些DockerFile指令再翻譯成真正的linux命令,其有自己的書寫方式和支持的命令
- Docker守護程序Dockerfile逐一運行指令,如有必要,將每個指令的結果提交到新鏡像,然后最終輸出新鏡像的ID。Docker守護程序將自動清理之前發送的上下文
- 每一條指令時獨立運行的,並會導致創建新鏡像,也就是說上一條指令與下一條指令不關聯
- 在構建的過程中,會利用緩存。已經運行過的指令會加載到緩存中,當新指令來時,只會運行指令,原來有的直接使用緩存中的。用於加速docker build過程
鏡像分層結構:
- 官方系統鏡像
- 個性化修改
- 基礎環境:nginx、php、jdk等
- 網頁資源、代碼、tomcat
例:
按照業務類型或系統類型等方式划分創建目錄環境,方便后期鏡像比較多的時候進行分類
mkdir /data/dockerfile/{web/{nginx,apache,tomcat,jdk},system/{centos,ubuntu,alpine,debian}} -p
Dockerfile 構建鏡像過程:
- 從基礎鏡像運行一個容器
- 執行一條指令,對容器做出修改
- 執行類似docker commit 的操作,提交一個新的中間鏡像層(可以利用中間層鏡像創建容器進行調試和排錯)
- 再基於剛提交的鏡像運行一個新容器
- 執行Dockerfile中的下一條指令,直至所有指令執行完畢
Dockerfile 文件格式:
文件名就必須叫Dockerfile,且有語法格式,文件名大小寫銘感
官方說明:https://docs.docker.com/engine/reference/builder/
系統幫助: man 5 dockerfile
文件說明:
- 每一行以Dockerfile的指令開頭,指令不區分大小寫,但是慣例使用大寫
- 使用 # 開始作為注釋
- 每一行只支持一條指令,每條指令可以攜帶多個參數
- 指令按文件的順序從上至下進行執行
- 每個指令的執行會生成一個新的鏡像層,為了減少分層和鏡像大小,盡可能將多條指令合並成一條指令
制作鏡像一般可能需要反復多次,每次執行dockfile都按順序執行,從頭開始,已經執行過的指令已經緩存,不需要再執行,如果后續有一行新的指令沒執行過,其往后的指令將會重新執行,所以為加速鏡像制作,將最常變化的內容放下dockerfile的文件的后面
docker build命令:
使用Dockerfile時,必須使用此命令進行自動構建成鏡像
docker build [OPTIONS] PATH | URL | -
選項:
路徑|url路徑|- -表示從標准輸入獲取
-f 文件 不指定時,默認在當前目錄下找Dockerfile,若指定,則在指定目錄構建
--force-rm 總是刪除中間層容器,創建鏡像失敗時,刪除臨時容器
--no-cache 不使用之前構建的鏡像緩存
-q 靜默模式構建,不輸出內容
--rm=true 鏡像創建成功后,刪除臨時容器
-t 設置構建的新鏡像名:項目名/鏡像名:版本
例:
#當前目錄構建
docker build -t xxx:v1 .
#指定文件構建
docker build -f /opt/xxx -t xxx:v1 .
docker history命令:
用於查看鏡像的構建過程
例:
#查看官方nginx鏡像的構建過程
docker history nginx:latest
Dockerfile相關指令:
ADD
COPY
ENV
EXPOSE
FROM
LABEL
STOPSIGNAL
USER
VOLUME
WORKDIR
FROM指令:
指定基礎鏡像,在基礎鏡像上進行定制
FROM就是指定基礎鏡像,此指令通常必需放在Dockerfile文件第一個非注釋行。后續的指令都是運行於此基准鏡像所提供的運行環境
基礎鏡像可以是任何可用鏡像文件,默認情況下,docker build會在docker主機上查找指定的鏡像文件,在其不存在時,則會從Docker Hub Registry 上拉取所需的鏡像文件.如果找不到指定的鏡像文件,docker build會返回一個錯誤信息
用法:
FROM [--platform=<platform>] <image> [AS <name>]
FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
FROM [--platform=<platform>] <image>[@<digest>] [AS <name>]
說明:
- --platform 指定鏡像的平台,比如: linux/amd64, linux/arm64, or windows/amd64
- tag 和 digest是可選項,如果不指定,默認為latest
關於FROM scratsch鏡像:
scratch是祖宗鏡像,所有的鏡像都源於此創建,也是一個空鏡像,一般要從零開始構建鏡像時,用此方法
參考鏈接:
- https://hub.docker.com/_/scratch?tab=description
- https://docs.docker.com/develop/develop-images/baseimages/
該鏡像是一個空的鏡像,可以用於構建busybox等超小鏡像,可以說是真正的從零開始構建屬於自己的鏡像
該鏡像在構建基礎鏡像(如debian和busybox)或超最小鏡像(僅包含一個二進制文件及其所需內容,如:hello-world)的上下文中最有用
用法:
FROM scratch 所有鏡像的起源鏡像,相當於Object類
FROM ubuntu
FROM ubuntu:bionic
FROM debian:buster-slim
LABEL指令:
指定鏡像元數據:作者...,以鍵值對方式
一個鏡像可以有多個label,可以寫在一行中,即多標簽寫法,可以減少鏡像的的大小,“\”符號換行
docker inspect查看到的label就是此處定義的
LABEL <key>=<value> <key>=<value> <key>=<value> ...
例:
LABEL author="hj" version="1.0"
或者:
LABEL auname="hj" \
version="1.0"
RUN指令:
在構建鏡像階段需要執行FROM,指定鏡像所支持的shell命令,一般各種基礎鏡像都支持普通shell命令
注意:
- RUN可以寫多個,每一個RUN指令都會建立一個鏡像層,所以盡可能合並成一條指令,比如將多個shell命令通過“&&”符號連接一起成為在一條指令
- 每個RUN都是獨立運行的,和前一個RUN無關
用法用法:
#shell格式: 支持環境變量
RUN <命令>
#exec格式:
RUN ["可執行文件", "參數1", "參數2"]
#exec格式指定其他shell:
RUN ["/bin/bash","-c","echo hello wang"]
#dockerfile:1.2加入,允許掛載文件、secrets、ssh-agent套接字、持久包管理緩存加快構建速度
RUN --mount=[type=<TYPE>][,選項1=參數,...]
類型:
bind #掛載文件系統
選項:
target #掛載目標路徑
source #from中的源路徑。默認為 from 的根目錄
from #源路徑來源,也就是上個鏡像層的文件系統,from指定的鏡像處得來
rw #讀寫,默認只讀權限掛載
cache #掛載一個臨時目錄來緩存編譯器和包管理器的目錄
選項:
id #標識符,默認是target
target #掛載路徑
ro #只讀權限
sharing #參數為:shared 、private或locked之一。默認shared,緩存裝載可由多個寫入器同時使用。private在有多個寫入器時創建新裝載。 locked暫停第二個寫入器,直到第一個寫入器釋放裝載
from #構建階段以用作緩存裝載的基礎。默認為空目錄
source #要掛載的from中的子路徑。默認為 from 的根目錄
mode #目錄權限,默認0755
uid、gid #用戶id,默認0
secret #允許生成容器訪問私鑰等安全文件
選項:
id
target #默認/run/secrets/ + id
required #如果設置為 true ,則當密鑰不可用時,指令會出錯。默認為 false
mode、uid、gid
ssh #允許生成容器通過SSH代理訪問SSH密鑰,並支持密碼
tmpfs #掛載 tmpfs文件系統
選項:
size #文件系統大小(使用的是內存,也就是內存使用大小)
target #掛載目標路徑
說明:
- shell格式中,<command>通常是一個shell命令,且以 "/bin/sh -c” 來運行它,這意味着此進程在容器中的PID不為1,不能接收Unix信號,因此,當使用docker stop <container>命令停止容器時,此進程接收不到SIGTERM信號
- exec格式中的參數是一個JSON格式的數組,其中<executable>為要運行的命令,后面的<paramN>為傳遞給命令的選項或參數;然而,此種格式指定的命令不會以"/bin/sh -c"來發起,因此常見的shell操作如變量替換、通配符(?,*等)替換將不會進行;不過,如果要運行的命令依賴於此shell特性的話,可替換為類似下面的格式
RUN ["/bin/bash", "-c", "<executable>", "<param1>"]
例:
RUN echo "<h1>web 123</h1>" >/var/www/html/index.html
RUN ["/bin/bash","-c","echo 123456"]
RUN yum install -y epel-release \
&& yum install -y nginx \
&& echo "hj's web page" > /usr/share/nginx/html/index.html
例2: 緩存go包
FROM golang
RUN --mount=type=cache,target=/root/.cache/go-build \
go build ...
例3:緩存 apt 包
FROM ubuntu
RUN rm -f /etc/apt/apt.conf.d/docker-clean; echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
apt update && apt-get --no-install-recommends install -y gcc
例4:容器訪問s3
vim Dockerfile
FROM python:3
RUN pip install awscli
RUN --mount=type=secret,id=aws,target=/root/.aws/credentials \
aws s3 cp s3://... ...
docker buildx build --secret id=aws,src=$HOME/.aws/credentials .
例5:運行多行腳本(高級用法)
#方法1
FROM debian
RUN <<EOT bash
set -ex
apt-get update
apt-get install -y vim
EOT
#方法2
FROM debian
RUN <<EOT
mkdir -p foo/bar
EOT
#方法3
FROM python:3.6
RUN <<EOT
#!/usr/bin/env python
print("hello world")
EOT
#方法4: 創建腳本,並運行
FROM alpine
COPY <<-"EOT" /app/script.sh
echo hello ${FOO}
EOT
RUN FOO=abc ash /app/script.sh
ENV指令:
以定義環境變量和值,會被后續指令(如:ENV,ADD,COPY,RUN等)通過\(KEY或\){KEY}進行引用,並在容器運行時保持
用法:
格式1:
此格式只能對一個key賦值,<key>之后的所有內容均會被視作其<value>的內容
ENV <key> <value>
格式2:
此格式可以支持多個key賦值,定義多個變量建議使用,減少鏡像層。還是 \ 位換行
ENV <key1>=<value1> <key2>=<value2> \
<key3>=<value3> ...
一次性變量:
RUN key=value cmd
高級變量賦值:
${key:-v1} key變量不存在,就賦值v1
${key:+v2} key變量存在,就賦值v2
引用變量:
RUN $key 或 RUN ${key}
例:
ENV user=hj pswd=123 \
xxx=123
env a1 123
ENV a2 qwe
COPY指令:
復制本地宿主機的到容器中
參考鏈接:https://golang.org/pkg/path/filepath/#Match
用法:
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"] 適用於路徑有空白字符的情況
COPY --from=分層鏡像名 <src> <dst>
說明:
- 可以是多個,可以使用通配符,通配符規則滿足Go語言的filepath.Match規則
- 只能復制在Dockerfile文件同級目錄下的文件,也就是以Dockerfile存放目錄為根目錄
- 如果是目錄,則其內部文件或子目錄會被遞歸復制,但目錄自身不會被復制
- 如果指定了多個,或在中使用了通配符,則dest必須是一個目錄,且必須以 / 結尾
- 可以是絕對路徑或者是 WORKDIR 指定的相對路徑
- 使用COPY指令,源文件的各種元數據都會保留。比如讀、寫、執行權限、文件變更時間等。也就是說可以加速構建速度,一般可用此優化鏡像構建
- 如果事先不存在,它將會被自動創建,這包括其父目錄路徑,即遞歸創建目錄
例1:
COPY test.txt /root/ 本地文件到容器root目錄
例2:
FROM node:18 AS build
WORKDIR /app
COPY package* yarn.lock ./
RUN yarn install
COPY public ./public
COPY src ./src
RUN yarn run build
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
例3:java分層構建
FROM maven AS build
WORKDIR /app
COPY . .
RUN mvn package
FROM tomcat
COPY --from=build /app/target/file.war /usr/local/tomcat/webapps
ADD指令:
增強版的COPY,不僅支持COPY,還支持自動解縮。可以將復制指定的到容器中的
用法:
#Dockerfile 1.3 開始支持 --chmod
ADD [--chown=<user>:<group>] [--chmod=<perms>] [--checksum=<checksum>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
#git克隆,無需在容器內執行git clone。--keep-git-dir配置是否創建.git
ADD [--keep-git-dir=<boolean>] git倉庫 <dir>
說明:
- 可以是Dockerfile所在目錄的一個相對路徑;也可是一個 URL;還可是一個 tar 文件(自動解壓)
- 可以是絕對路徑或者是 WORKDIR 指定的相對路徑
- 如果是目錄,只復制目錄中的內容,而非目錄本身
- 如果是一個 URL ,下載后的文件權限自動設置為 600
- 如果為URL且不以/結尾,則指定的文件將被下載並直接被創建為,如果以“\”結尾,則文件名URL指定的文件將被直接下載並保存為/<filename>
- 如果是一個本地文件系統上的打包文件,如: gz, bz2 ,xz ,它將被解包 ,其行為類似於"tar -x"命令, 但是通過URL獲取到的tar文件將不會自動展開
- 如果有多個,或其間接或直接使用了通配符,則必須是一個以/結尾的目錄路徑;如果不以/結尾,則其被視作一個普通文件,的內容將被直接寫入到
例:
ADD a.tgz /opt/ 文件傳到容器的/opt/目錄后自動解壓
CMD指令:
容器中需要持續運行的進程一般只有一個,CMD用來指定啟動容器時默認執行的一個命令,且其運行結束后,容器也會停止,所以一般CMD 指定的命令為持續運行且為前台命令
RUN是構建時運行的指令,CMD是容器運行時運行的指令
如果docker run沒有指定任何的執行命令或者dockerfile里面也沒有ENTRYPOINT,那么開啟容器時就會使用執行CMD指定的默認的命令
每個Dockerfile只能有一條CMD命令。如指定了多條,只有最后一條被執行
如果啟動容器時用 docker run xxx cmd 指定運行的命令,則會覆蓋 CMD 指定的命令
用法:
#exec格式執行:推薦使用,且不支持環境變量
CMD ["命令","param1","param2"]
#sh格式執行:交互式使用,支持環境變量
CMD command param1 param2
#給entrypoint命令的傳遞參數:
CMD ["param1","param2"]
例:
CMD ["nginx","-g","daemon off;"]
CMD ["curl","-s","https://ip.cn"] 同一文件中,只有此命令生效
ENTRYPOINT指令:
類似CMD,配置容器啟動后執行的命令及參數
如果與cmd命令共存,則cmd的內容當做參數傳遞給entrypoint
docker run執行時,可手動傳參,其優先級順序:
-e > --env-file > ENV
用法:
#exc執行
ENTRYPOINT ["executable", "param1", "param2"]
#sh執行
ENTRYPOINT command param1 param2
說明:
- docker run -e/--env-file 不能覆蓋ENTRYPOINT的參數,而是把傳遞的參數追加在ENTRYPOINT原有的參數后面
- 如果docker run 后面沒有額外參數,但是dockerfile中的CMD里有(即上面CMD的第三種用法),即Dockerfile中即有CMD也有ENTRYPOINT,那么CMD的全部內容會作為ENTRYPOINT的參數
- 如果docker run 后面有額外參數,同時Dockerfile中即有CMD也有ENTRYPOINT,那么docker run 后面的參數覆蓋掉CMD參數內容,最終作為ENTRYPOINT的參數
- 可以通過docker run --entrypoint string 參數在運行時替換,注意string不要加空格
- 使用CMD要在運行時重新寫命令本身,然后在后面才能追加運行參數,ENTRYPOINT則可以運行時無需重寫命令就可以直接接受新參數
- 每個Dockerfile中只能有一個ENTRYPOINT,當指定多個時,只有最后一個生效
例:
#CMD的內容做參數傳給ENTRYPOINT的命令
CMD ["-g","daemon off;"]
ENTRYPOINT ["nginx"]
#命令行指定,優先級最高
docker run -d --entrypoint tail hj-nginx -f /etc/hosts
例:腳本指定環境變量動態生成配置文件內容(高級玩法)
#dockerfile
vim Dockerfile
FROM nginx:1.16-alpine
LABEL maintainer="hj.com"
ENV DOC_ROOT='/data/website/'
ADD index.html ${DOC_ROOT}
ADD entrypoint.sh /bin/
EXPOSE 80/tcp 8080
RUN apk nginx
CMD ["/usr/sbin/nginx","-g", "daemon off;"]
ENTRYPOINT [ "/bin/entrypoint.sh"]
#entrypoint腳本,動態配置nginx並啟動
vim entrypoint.sh
#!/bin/sh
cat > /etc/nginx/conf.d/www.conf <<EOF
server {
server_name ${HOSTNAME};
listen ${IP:-0.0.0.0}:${PORT:-80};
root ${DOC_ROOT:-/usr/share/nginx/html};
}
EOF
exec "$@"
解析:
- CMD的內容變成參數,傳給ENTRYPOINT,而后者執行entrypoint.sh腳本時,把CMD的內容當做變量傳給正在執行的entrypoint.sh,此時“$@”變量獲取的參數就是:/usr/sbin/nginx -g daemon off;
- entrypoint.sh腳本執行時,從上往下運行,基於shell的變量高級賦值,生成配置文件,最后exec執行有$@獲取的參數,也就是:
exec /usr/sbin/nginx -g daemon off
ARG指令:
在build階段指定變量,和ENV不同的是,容器運行時不會存在這些環境變量,只在構建時生效
用法:
ARG <name>[=<default value>]
docker build --build-arg <參數名>=<值>
說明:
- 如果變量名與ENV同名,則ENV覆蓋ARG
- 支持做最開始的變量定義,也就是寫在FROM之前
例:
vim base/Dockerfile
FROM busybox
ARG author=hj
docker build --build-arg author="hj-v1" -t 鏡像
例:
vim xx/Dockerfile
ARG version=1.0
FROM base:${version}
VOLUME指令:
VOLUME實現的是匿名數據卷,無法指定宿主機路徑和容器目錄的掛載關系
通過docker rm -fv <容器ID> 可以刪除容器的同時刪除VOLUME指定的卷
宿主機目錄為:
/var/lib/docker/volumes/<volume_id>/_data
指定容器內的掛載目錄后,物理機自動在該路徑下創建目錄,卷id是隨機生成的,_data就是容器內掛載的目錄名,卷id以后就是掛載點根目錄
當容器刪除時,容器內在/data/下存的文件,還保留在物理機的/var/lib/docker/volumes/卷id/_data/
用法:
VOLUME <容器內路徑>
VOLUME ["<容器內路徑1>", "<容器內路徑2>"...]
docker rm -v 容器 刪除容器時,刪除對應的匿名卷
例:
VOLUME ["/data","/data2"]
EXPOSE指令:
EXPOSE僅僅是聲明容器打算使用什么端口而已,並不會真正暴露端口,即不會自動在宿主進行端口映射
啟動容器是還是需要-p/-P來指明與物理機映射的端口才能真正分配端口
注意:
- 即使 Dockerfile沒有EXPOSE 端口指令,也可以通過docker run -p 臨時暴露容器內程序真正監聽的端口,所以EXPOSE 相當於指定默認的暴露端口,可以通過docker run -P 進行真正暴露
用法:
EXPOSE <port>[/ <protocol>] [<port>[/ <protocol>] ..]
說明:
- 可為tcp或udp二者之一,默認為TCP協議
例:
EXPOSE 80 443/tcp
EXPOSE 3306
WORKDIR指令:
為后續的 RUN、CMD、ENTRYPOINT 指令配置工作目錄,當容器運行后,進入容器內WORKDIR指定的默認目錄
如果目錄不存在,會自動創建
用法:
WORKDIR /path/to/workdir
說明:
- 可以使用多個WORKDIR指令,后續命令如果參數是相對路徑,則會基於之前命令指定的路徑
例:
WORKDIR /web
RUN echo 123456 > ts.txt
WORKDIR /a
WORKDIR b 切換多級目錄,/a/b
ONBUILD指令:
可以用來配置構建當前鏡像的子鏡像時,會自動觸發執行的指令,但在當前鏡像構建時,並不會執行,即延遲到子鏡像構建時才執行
用法:
OPTIONS 指令 命令
例:
#A鏡像為父鏡像: 不會在父鏡像執行
FROM ubuntu
ONBUILD RUN echo 123456 > 1.txt
ONBUILD RUN cat /etc/hosts
#B鏡像為子鏡像,引用B:
FROM A
#引用后,首先執行父鏡像的ONBUILD指令的內容
RUN echo 123456 > 1.txt
RUN cat /etc/hosts
USER指令:
指定運行容器時的用戶名或 UID,后續的 RUN 也會使用指定用戶
用戶必須是事先就有的,否則報錯,沒有指定時默認root
用法:
USER <user>[:<group>]
USER <UID>[:<GID>]
例:
RUN useradd -r mysql
USER mysql
HEALTHCHECKH指令:
容器健康檢查,有錯誤是自動刪除容器重新創建
用法:
#設置檢查容器健康狀況的命令
HEALTHCHECK [選項] CMD <命令>
選項:
--interval=間隔 兩次檢測時間間隔
--timeout=時長 超時時長,超過為失敗,默認30s
--retries=次數 失敗次數
--start-period=時間 檢查開始的時間,默認0s(立即檢查)
#如果基礎鏡像有健康檢查指令,使用這行可以屏蔽掉其健康檢查指令
HEALTHCHECK NONE
返回狀態結果說明:
- 0: 健康狀態
- 1: 非正常工作狀態
- 2: 不使用此退出狀態碼
例:
FROM ubuntu
RUN apt install -y nginx
#容器健康檢測,5秒一次,超時3秒,執行curl命令檢查
HEALTHCHECK --interval 5s --timeout=3s CMD curl -fs http://127.0.0.1 ||exit 1
STOPSIGNALZ指令:
設置容器退出時的信號,支持系統所有信號
用法:
STOPSIGNAL 信號
SHELL指令:
更改容器的默認shell,一般默認,除非win系統時改成cmd或者powershell
linux的默認使用sh -c ,win默認使用cmd /s /c
SHELL指令可以出現多次。每個SHELL指令將覆蓋所有先前的SHELL指令,並影響所有后續的指令
用法:
SHELL ["executable", "parameters"]
例:
FROM microsoft/windowsservercore
RUM echo default
RUN powershell -command Write-Host default
#powershell模式
SHELL ["powershell", "-command"]
RUN Write-Host hello
#cmd模式
SHELL ["cmd", "/S", "/C"]
RUN echo hello
#sh模式
SHELL ["sh","-c"]
RUN echo shell
.dockerignore文件:
當用copy和add復制文件時,通配符會把所有文件都復制,此時可以在.dockerignore文件中定義哪些文件不需要復制(此文件只能定義忽略的)
通配符規則基於go語言
官方文檔:https://docs.docker.com/engine/reference/builder/#dockerignore-file
go語言通配符規則:https://golang.org/pkg/path/filepath/#Match
完整語法:
# | 以#開頭的行為注釋 |
* | 任意字符 |
? | 任意單個字符 |
\ | 表示 \轉義 |
** | 取反通配符,**/*.go,表示任何目錄下的.go結尾文件都不處理 |
! | 表示取反,可用於排除例外情況 |
例:
vim .dockerignore
! readme* 不要所有的readme開頭的文件
*.txt #.txt文件都忽略