用Dockerfile构建镜像以及如何制作跨平台镜像
Dockerfile 简介
构建Docker镜像有两种方法:
- 一种是利用Dockerfile编译构建,命令格式为
docker build --pull -t $(REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG) .
[docker-build官指]https://docs.docker.com/engine/reference/commandline/build/ - 一种是用正在运行的容器commit为目标镜像,命令格式为
docker commit $(DockerID) $(REGISTRY)/$(IMAGE_NAME):$(IMAGE_TAG)
[docker-commit官指]https://docs.docker.com/engine/reference/commandline/commit/#commit-a-container
第一种方法有迹可循,是推荐的方法。第二种方法适用于对Docker命令不熟悉的亲,对运行的容器配置完成后,进行打包成新的镜像。
这里介绍利用Dockerfile构建镜像,喜欢看官方文档的亲请点这里[官方Dockerfile用法说明]https://docs.docker.com/engine/reference/builder/。
Dockerfile是一个Docker镜像的描述文件,我们可以理解成火箭发射的A、B、C、D…的步骤。Dockerfile其内部包含了一条条的指令,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
一个Dockerfile示例如下,该文件命名为Dockerfile, 注意只命名为Dockerfile,假设该Dockerfile所在的文件夹是/root/k8s/:
# 基于debian镜像,版本号为jessie
FROM debian:jessie
# 创建目录
RUN mkdir /var/log -p
# 拷贝kubemark到容器内,如果是压缩文件则会解压
# 注意这里第一个参数是主机文件所在位置,相对位置是当前make执行的目录,而不是Dockerfile存放的目录
COPY kubemark /kubemark
COPY voyage-agent /voyage-agent
# 拷贝文件到容器内,如果没有该目录会自动创建该目录。ADD 支持解压文件,较COPY复杂,若只是简单的拷贝建议用COPY
ADD voyage-cni /opt/cni/bin/
ADD loopback /opt/cni/bin/
ADD 1-voyage.conf /etc/cni/net.d/
#复制该脚本至镜像中,并修改其权限
ADD run.sh /run.sh
RUN chmod 775 /run.sh
#当启动容器时执行的脚本文件, 只能有一条CMD,如果有多条(建议写在一个脚本里),则只有第一条生效. CMD和RUN执行的时机不同,CMD是在容器启动之后执行的。
CMD ["/run.sh"]
由上可知,Dockerfile结构大致分为四个部分:
(1)基础镜像信息
(2)维护者信息
(3)镜像操作指令
(4)容器启动时执行指令
Dockerfile每行支持一条指令,每条指令可带多个参数,支持使用以#号开头的注释。
- 编译镜像的命令为 docker build -t mydebian:8 /root/k8s/
- CMD里面如果命令有多个参数,要像这样写:CMD ["sleep", "100"]
如果需要到墙外下载部分安装包,需要配置代理,在Dockerfile的头尾进入如下配置:
ENV http_proxy http://172.18.8.7:7890
ENV https_proxy http://172.18.8.7:7890
.....
RUN unset http_proxy && unset https_proxy
在nginx容器中安装ping、nslookup、ip、curl 等工具
#先进入基础镜像docker.io/nginx:latest的容器里面,然后执行如下命令,然后docker commit <podid> <imagetag>
apt update
#ping
apt install inetutils-ping
#nslookup
apt install dnsutils
#ifconfig
apt install net-tools
#ip
apt install iproute2
#curl
apt install curl
镜像测试
docker run -ti <image-name>
查看镜像的编译历史
例如,我想查看镜像calico/node:v3.16.5的Dockfile的历史记录
docker history calico/node:v3.16.5 --no-trunc
制作跨平台镜像
大多数情况下我们需要部署服务的环境是x86系统,但是有时也会把容器部署在arm环境下,这时就需要制作同一个镜像希望能支持跨平台的运行。因为如果是在x86机器上用docker build命令编译镜像运行在arm机上会报错:standard_init_linux.go:211: exec user process caused "exec format error"
- 首先在编译镜像的主机上打开docker的experimental属性:在docker的启动命令中加上参数
--experimental
标志或者在/etc/docker/daemon.json中加入"experimental"=true.重启docker进程后,用命令docker version查看Experimental属性为true - 分别在x86主机(172.18.8.210:5555/doric-server-x86:0.1)和arm主机上(172.18.8.210:5555/doric-server-arm:0.1)用docker build命令编译镜像并上传到镜像仓库
- docker manifest create --insecure 1.2.3.4:5555/app:0.1 1.2.3.4:5555/app-x86:0.1 1.2.3.4:5555/app-arm:0.1
注意,这里要加上参数--insecure否则会报错no such manifest:1.2.3.4:5555/doric-server-x86:0.1,另外要确保各个平台的镜像都已经上传 - docker manifest inspect 1.2.3.4:5555/doric-server:0.1 查看信息,如果平台架构不正确需要打上正确的annotation
docker manifest annotate 1.2.3.4:5555/app:0.1 1.2.3.4:5555/app-arm:0.1 --arch arm64
然后再次使用命令docker manifest inspect 1.2.3.4:5555/doric-server:0.1 查看信息是否正确 - docker manifest push 1.2.3.4:5555/doric-server:0.1
我在这一步报错:error mounting 1.2.3.4:5555/app-armxxx to 1.2.3.4:5555/app:0.1,经查是编译arm镜像的基础镜像不是arm平台的。这里注意,如果你下载的镜像是支持跨平台的,那么你在那个平台上docker pull只能下载该平台架构的镜像。因此在编译跨平台镜像时,基础镜像要现下,要新鲜的。
如果报错"failed to configure transport: error pinging v2 registry: Get https://1.2.3.4:5555",加上--insecure参数再push.