docker鏡像制作


鏡像制作

說明:

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標記創建不同版本的鏡像以及創建不同版本的容器

構建鏡像大致步驟:

  1. 下載一個系統的官方基礎鏡像,如: CentOS 或 Ubuntu
  2. 基於基礎鏡像啟動一個容器,並進入到容器
  3. 在容器里面做配置操作
    • 安裝基礎命令
    • 配置運行環境
    • 安裝服務和配置服務
    • 放業務程序代碼
  4. 提交為一個新鏡像 docker commit
  5. 基於自己的的鏡像創建容器並測試訪問

基於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

image

基於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

image

例:

按照業務類型或系統類型等方式划分創建目錄環境,方便后期鏡像比較多的時候進行分類

mkdir /data/dockerfile/{web/{nginx,apache,tomcat,jdk},system/{centos,ubuntu,alpine,debian}} -p

Dockerfile 構建鏡像過程:

  1. 從基礎鏡像運行一個容器
  2. 執行一條指令,對容器做出修改
  3. 執行類似docker commit 的操作,提交一個新的中間鏡像層(可以利用中間層鏡像創建容器進行調試和排錯)
  4. 再基於剛提交的鏡像運行一個新容器
  5. 執行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是祖宗鏡像,所有的鏡像都源於此創建,也是一個空鏡像,一般要從零開始構建鏡像時,用此方法

參考鏈接:

該鏡像是一個空的鏡像,可以用於構建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文件都忽略


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM