首页 > 技术文章 > 用Dockerfile构建镜像以及如何制作跨平台镜像

janeysj 2020-04-14 16:34 原文

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到容器内,如果是压缩文件则会解压
COPY kubemark /kubemark
COPY voyage-agent  /voyage-agent

# 拷贝文件到容器内,如果没有该目录会自动创建该目录
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"]

在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"

  1. 首先在编译镜像的主机上打开docker的experimental属性:在docker的启动命令中加上参数--experimental标志或者在/etc/docker/daemon.json中加入"experimental"=true.重启docker进程后,用命令docker version查看Experimental属性为true
  2. 分别在x86主机(172.18.8.210:5555/doric-server-x86:0.1)和arm主机上(172.18.8.210:5555/doric-server-arm:0.1)用docker build命令编译镜像并上传到镜像仓库
  3. 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,另外要确保各个平台的镜像都已经上传
  4. 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 查看信息是否正确
  5. 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.

推荐阅读