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