1 dockerfile基本介绍

1.1 什么是dockerfile

Dockerfile 是⼀个⽂本⽂件,⾥⾯包含了⼀条条的指令,每⼀条指令都对应构建⼀个镜像层。按顺序执⾏这些指令,就可以⾃动构建出⼀个Docker镜像。这些镜像层是堆叠的,每⼀层都是基于前⼀层构建的增量。如下图所示,Dockerfile 的执⾏会⼀层层构建镜像层,最终形成完整的镜像。

七、docker镜像构建_bash

1.2 dockerFile构建过程解析

1.2.1 Dockerfile内容基础知识

  • 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
  • 指令按照从上到下,顺序执行
  • #表示注释
  • 每条指令都会创建一个新的镜像层,并对镜像进行提交

1.2.2 Docker执行Dockerfile的大致流程

(1)docker从基础镜像运行一个容器

(2)执行一条指令并对容器作出修改

(3)执行类似docker commit的操作提交一个新的镜像层

(4)docker再基于刚提交的镜像运行一个新容器

(5)执行dockerfile中的下一条指令直到所有指令都执行完成

1.2.3 小总结

从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段,

  • Dockerfile是软件的原材料
  • Docker镜像是软件的交付品
  • Docker容器则可以认为是软件的运行态。

Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。

七、docker镜像构建_docker_02

  • Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;  
  • Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时,会真正开始提供服务;
  • Docker容器,容器是直接提供服务的。

2 dockerfile语法

2.1 FROM

FROM 指令是⽤来指定基础镜像,基础镜像可以是官⽅远程仓库中的镜像,也可以是本地构建的镜像。

FROM语法示例: FROM ubuntu:18.04

2.2 MAINTAINER  

指定镜像的作者信息

2.3 RUN

指定在当前镜像构建过程中要运行的命令

RUN命令运行的基本都是linux自带的,第三方命令比如mysql之类的是无法在这里面执行的 

包含两种模式  

2.3.1 Shell  

RUN echo hello && echo world

2.3.2 exec 模式  

RUN ["executable","param1","param2"]

RUN ["/bin/bash","-c","echo hello"]  

等价于/bin/bash -c echo hello

cat dockerfile
FROM centos:latest
MAINTAINER qingchen
RUN echo hello && echo world
RUN ["/bin/sh","-c","echo qingchen"]

七、docker镜像构建_centos_03

2.4 EXPOSE 指令  

仅仅只是声明端口。

当启动容器使用-P随机端口时,会暴露这些端口

2.5 ADD

将宿主机目录下的文件拷贝进镜像且ADD命令会自动处理URL和解压tar压缩包

如果镜像目录不存在,还会进行创建

2.6 COPY

#类似ADD,拷贝文件和目录到镜像中,但是不执行解压,如果镜像目录不存在,则复制的文件就是就改名成目录名

将从构建上下文目录中 的文件/目录复制到新的一层的镜像内的位置

COPY src dest

COPY ["src", "dest"]

[root@docker dockerfile]# cat dockerfile
FROM centos:v7.4
MAINTAINER qingchen
RUN echo hello && echo world
RUN ["/bin/bash","-c","echo hello"]
ADD apache-tomcat-9.0.41.tar.gz /data1
COPY apache-tomcat-9.0.41.tar.gz /tmp

docker build -t docker-add-copy:v2 .

docker run -it docker-add-copy:v2 /bin/bash
[root@dc05133ea90e /]# cd /data1/
[root@dc05133ea90e data1]# ls
apache-tomcat-9.0.41
[root@dc05133ea90e data1]# cd /tmp
[root@dc05133ea90e tmp]# ls
apache-tomcat-9.0.41.tar.gz

尽可能的使用 COPY,因为COPY 的语义很明确,就是复制文件而已,而 ADD 则包含了更复杂的功能,其行为也不一定很清晰。最适合使用 ADD 的场合,就是所提及的需要自动解压缩的场合。

另外需要注意的是,ADD 指令会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。

因此在COPY 和 ADD 指令中选择的时候,可以遵循这样的原则,所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD

在使用该指令的时候还可以加上--chown=<user>:<group> 选项来改变文件的所属用户及所属组。

2.7 VOLUME  

VOLUME ["/data1","/data2"]

#容器数据卷,用于数据保存和持久化工作

通过dockerfile的 VOLUME 指令可以在镜像中创建挂载点,当创建对应容器时会自动进行挂载,不需要docker run的时候-v指定

还有一个区别是,通过 VOLUME 指令创建的挂载点,无法指定主机上对应的目录,是自动生成的。

[root@docker dockerfile]# cat dockerfile
FROM centos:v7.4
MAINTAINER qingchen
RUN echo hello && echo world
RUN ["/bin/bash","-c","echo hello"]
VOLUME ["/data1","/data2"]

docker build -t docker-volume:v2 .

[root@docker dockerfile]# docker run -itd docker-volume:v2 /bin/bash
7cb8600527cc64dd480d54ff2911f47252547bba07854bfa6e683ac8c9ee448c
[root@docker dockerfile]# docker inspect 7cb8600527

        "Mounts": [
            {
                "Type": "volume",
                "Name": "42f7375398ac33ed85022ec076a72812aedb8db46ce065b461fb1e1398155da6",
                "Source": "/data/docker/volumes/42f7375398ac33ed85022ec076a72812aedb8db46ce065b461fb1e1398155da6/_data",
                "Destination": "/data1",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            },
            {
                "Type": "volume",
                "Name": "b5ec37095352e703092eb2ce749651ec186b71842ffe60e015e913771f2aa9eb",
                "Source": "/data/docker/volumes/b5ec37095352e703092eb2ce749651ec186b71842ffe60e015e913771f2aa9eb/_data",
                "Destination": "/data2",
                "Driver": "local",
                "Mode": "",
                "RW": true,
                "Propagation": ""
            }

2.8 WORKDIR  

WORKDIR 指令是⽤来设置⼯作⽬录,后续的 RUN、CMD、ENTRYPOINT、COPY 以及 ADD 指令都会在这个⽬录下执⾏。如该目录不存在,WORKDIR 会帮你建立目录。指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点

一个dockerfile里面可以设置多次,也可以使用环境变量的地址,如果你的 WORKDIR 指令使用的相对路径,那么所切换的路径与之前的 WORKDIR 有关

指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。  

docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。

进入Docker运行的容器的默认目录也是这个 

WORKDIR语法示例: WORKDIR /data

2.9、ENV  

这个指令很简单,就是设置环境变量而已,无论是后面的其它指令,如 RUN,还是运行时的应用,都可以直接使用这里定义的环境变量。

ENV 指令⽤来设置环境变量。无论是后面的RUN、CMD 或者 ENTRYPOINT 指令,还是运行时应用,都可以直接使⽤这个环境变量,

ENV语法示例:

ENV PG_MAJOR 9.3 RUN yum install postgresql-${PG_MAJOR} -y

2.10 ARG

构建参数和ENV 的效果一样,都是设置环境变量。所不同的是,ARG 所设置的构建环境的环境变量,在将来容器运行时是不会存在这些环境变量的。但是不要因此就使用 ARG 保存密码之类的信息,因为 docker history 还是可以看到所有值的。

Dockerfile 中的 ARG 指令是定义参数名称,以及定义其默认值。该默认值可以在构建命令 docker build 中用 --build-arg <参数名>=<值> 来覆盖。

多阶段构建尤其要注意:

ARG 指令有生效范围,如果在 FROM 指令之前指定,那么只能用于 FROM 指令中。

要想FROM之后使用,你必须在 FROM 之后再次指定 ARG

2.11 HEALTHCHECK

HEALTHCHECK 指令是告诉Docker 应该如何进行判断容器的状态是否正常,这是 Docker 1.12 引入的新指令。 

HEALTHCHECK语法示例: HEALTHCHECK [OPTIONS] CMD command

例如,每30s左右检查⼀次⽹站服务是否能够在三秒内提供访问(默认 --retries 尝试3次,如果都不成功则失败):

HEALTHCHECK --interval=30s --timeout=3s \

CMD curl -f http://localhost/ || exit 1

# 命令的退出状态表示容器的健康状态。可能的值是:

  • 0:成功 - 容器健康并可以使⽤
  • 1:不健康——容器没有正常⼯作
  • 2:保留 - 不要使⽤此退出代码

和 CMD, ENTRYPOINT 一样,HEALTHCHECK 只可以出现一次,如果写了多个,只有最后一个生效。

2.12 ONBUILD  

ONBUILD 是一个特殊的指令,它后面跟的是其它指令,比如 RUN, COPY 等,而这些指令,在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像,去构建下一级镜像的时候才会被执行。

Dockerfile 中的其它指令都是为了定制当前镜像而准备的,唯有 ONBUILD 是为了帮助别人定制自己而准备的。

2.13 CMD  

#指定一个容器启动时要运行的命令,命令方式和RUN类似

CMD["executable","param1","param2"](exec 模式)  

CMD command (shell 模式)  

CMD ["param1","param2"](作为 ENTRYPOINT 指令的默认参数)

Dockerfile #中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换

[root@docker dockerfile]# cat dockerfile
FROM centos:v7.4
MAINTAINER qingchen
RUN echo hello && echo world
RUN ["/bin/bash","-c","echo hello"]
VOLUME ["/data1","/data2"]

docker build -t docker-cmd:v2 .
[root@docker dockerfile]# docker run -it docker-cmd:v2
test3
当docker run带参数时
[root@docker dockerfile]# docker run -it docker-cmd:v2 echo test4
test4

2.14 ENTRYPOINT

类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被

当作参数送给 ENTRYPOINT 指令指定的程序。  

但是, 如果运行 docker run 时使用了 --entrypoint 选项,将覆盖 entrypoint 指令指定的程序。  

优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。  

注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效

ENTERYPOINT ["executable","param1","param2"](exec 模式)  

ENTERYPOINT command (shell 模式)

当存在多个ENTRYPOINT时
[root@docker dockerfile]# cat dockerfile
FROM centos:v7.4
MAINTAINER qingchen
RUN echo hello && echo world
RUN ["/bin/bash","-c","echo hello"]
ENTRYPOINT ["/bin/bash","-c","echo test2"]
ENTRYPOINT ["/bin/bash","-c","echo test3"]

docker run -it docker-en:v1 .
[root@docker dockerfile]# docker run  -it docker-en:v1
test3
当同时存在ENTRYPOINT和CMD时
[root@docker dockerfile]# cat dockerfile
FROM centos:v7.4
MAINTAINER qingchen
RUN echo hello && echo world
RUN ["/bin/bash","-c","echo hello"]
ENTRYPOINT ["echo"]
CMD ["hello"]

docker build -t docker-en:v3 .
[root@docker dockerfile]# docker run  -it docker-en:v3
hello
当同时存在ENTRYPOINT和CMD,并且docker run指定了参数时
[root@docker dockerfile]# docker run  -it docker-en:v3 tom
tom

如果有多个命令在容器运行时需要执行,可以写进一个脚本,ENTRYPOINT或者CMD直接sh这个脚本

3 dockerfile实践

3.1 nginx

构建⼀个基于CentOS环境的Nginx镜像
1、dockerfile文件
#指定基础镜像
FROM hub.atomgit.com/library/centos:7
#指定镜像的作者
MAINTAINER qingchen
#将原来的yum源做备份
RUN mkdir /tmp/repo.bk && mv /etc/yum.repos.d/* /tmp/repo.bk
#配置yum源
#COPY ./epel.repo /etc/yum.repos.d/epel.repo
COPY ./CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo
#更新依赖
RUN yum clean all && \
    yum makecache && \
    yum install wget sl gcc pcre-devel zlib-devel make -y
#定义nginx版本
ARG NGX_VERSION=1.16.0
#设定工作目录
WORKDIR /usr/local
#上传nginx源码包
ADD nginx-${NGX_VERSION}.tar.gz ./
#进行编译
RUN mkdir -p /app && \
    cd nginx-${NGX_VERSION} && \
    ./configure --prefix=/app/nginx-${NGX_VERSION} && \
    make && make install
#初始化动作
RUN mkdir /code && \
    ln -s /app/nginx-${NGX_VERSION} /app/nginx
#配置文件和代码
COPY index.html /code/index.html
COPY nginx.conf /app/nginx/conf/nginx.conf
#配置日志输出,日志要重定向输出到stdout,否则无法看到容器日志输出
#一定要创建/var/log/nginx,默认没这个目录,软连接做不了
RUN mkdir /var/log/nginx -p && \
    ln -sf /dev/stdout /var/log/nginx/access.log && \
    ln -sf /dev/stderr /var/log/nginx/error.log
#暴露端口
EXPOSE 80 443
#数据卷
volume /code
#健康检查
HEALTHCHECK --interval=30s --timeout=3s \
            CMD curl -f http://localhost/ || exit 1
#启动服务
#CMD ["/app/nginx/sbin/nginx","-g","daemon off;"]
#CMD ['/bin/bash','-c ','/app/nginx/sbin/nginx -g daemon off']
ENTRYPOINT ["/app/nginx/sbin/nginx","-g","daemon off;"]

2、配置index.html
echo hello world > index.html

3、配置nginx.conf
worker_processes auto;
error_log  /var/log/nginx/error.log warn;
events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/nginx/access.log  main;
    server {
        listen 80;
        server_name example.com;
        root /code;

        location / {
            index index.html;
        }
    }
}

4、构建镜像

docker build -t nginx:v1 .

七、docker镜像构建_tomcat_04

5、运行镜像

docker run -P -itd --name nginxv1 nginx:v1

七、docker镜像构建_5e_05

七、docker镜像构建_centos_06

6、模拟访问

curl http://10.10.10.2/index.html

curl http://10.10.10.2/error.html

7、日志查看

七、docker镜像构建_bash_07

3.2 tomcat

[root@docker dockerfile]# cat dockerfile
FROM centos:latest
MAINTAINER qingchen
#安装软件unzip
RUN yum install -y unzip
#将/tmp设置为工作目录
WORKDIR /tmp
COPY jdk1.8.0_171.zip /tmp
#解压JDK并移动到/usr/local目录下
RUN unzip jdk1.8.0_171.zip && mv jdk1.8.0_171 /usr/local
ADD apache-tomcat-9.0.41.tar.gz /tmp
#改名为tomcat并移动到/usr/local目录下
RUN mv apache-tomcat-9.0.41 tomcat && mv tomcat /usr/local
#暴露对外端口8080
EXPOSE 8080
#设置环境变量
ENV JAVA_HOME /usr/local/jdk1.8.0_171
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV CATALINA_HOME /usr/local/tomcat
ENV CATALINA_BASE /usr/local/tomcat
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
#设置工作目录,容器启动后默认工作目录
WORKDIR /usr/local/tomcat
#启动tomcat
CMD /usr/local/tomcat/bin/startup.sh && tail -F /usr/local/tomcat/logs/catalina.out

docker build -t cantos-tomcat:v1 .
docker run -itd -P cantos-tomcat:v1

4 dockerfile场景实践

4.1 分层构建概念

通常Docker 镜像采⽤分层构建的⽅案。也就是⾸先构建基础运⾏环境镜像,然后在其之上依次构建中间件镜像和业务镜像。具体可以分为以下⼏层:

  • 基础系统镜像:选择⼀个官⽅的操作系统镜像,如 Ubuntu、CentOS 等。这⼀层完成基础 OS 环境和配置。
  • 语⾔运⾏时镜像:基于 OS 基础镜像,安装 Python、Node.js 或 Java 等语⾔运⾏环境和依赖库。这⼀层提供语⾔运⾏环境。
  • 应⽤镜像:基于语⾔运⾏时镜像,安装应⽤服务器如 Nginx、Apache 或Tomcat 等。这⼀层提供中间件和Web服务器。
  • 业务镜像:基于前⾯层,部署业务应⽤代码及其依赖。这⼀层提供业务应⽤及其配置。

七、docker镜像构建_centos_08

这种分层构建⽅案的好处在于:

  • 复⽤:每⼀层可以被下层重复使⽤,不需要重复配置基础环境。
  • 隔离:每⼀层只需要关注⾃身层的功能,不依赖其他层的实现细节。
  • 缓存:每⼀层的构建缓存可以被直接使⽤,提⾼构建效率。
  • 灵活性:不同的层可以⾃由组合,满⾜不同的使⽤场景。

总之,采⽤分层构建⽅案可以⼤⼤优化

4.2 构建基础镜像

基于centos7构建⼀个基础的镜像,该镜像安装⼀些常⽤⼯具

1、编写Dockerfile
cat dockerfile
#指定基础镜像
FROM hub.atomgit.com/library/centos:7
#指定镜像的作者
MAINTAINER qingchen
#将原来的yum源做备份
RUN mkdir /tmp/repo.bk && mv /etc/yum.repos.d/* /tmp/repo.bk
#配置yum源
#COPY ./epel.repo /etc/yum.repos.d/epel.repo
COPY ./CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo
#更新依赖
RUN yum clean all && \
    yum makecache && \
    yum install -y vim tcpdump telnet net-tools wget curl git unzip iproute
#设置时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

2、执⾏镜像构建
docker build -t centos7_base:v1.0 .

七、docker镜像构建_bash_09

4.3 构建JAVA环境镜像

基于基础构建⼀个Oracle java1.8 的应⽤镜像,该镜像会安装java相关应⽤

1、编写Dockerfile
cat dockerfile
#指定基础镜像
FROM centos7_base:v1.0
#指定镜像的作者
MAINTAINER qingchen
#设置环境变量
ENV JDK_VERSION=jdk-8u351-linux-x64
#拷贝JDK安装包
COPY ./${JDK_VERSION}.rpm .
#安装清理
RUN rpm -ivh ${JDK_VERSION}.rpm && \
    rm -f ${JDK_VERSION}.rpm

2、构建镜像
docker build -t jdk1.8:v1.0 .

七、docker镜像构建_docker_10

4.4 构建JAVA业务镜像

1、下载代码,进⾏代码编译
mvn package

2、编写Dockerfile(⼀般Dockerfile在业务代码中,便于构建镜像和后续的CI与CD)
cat Dockerfile
FROM jdk1.8:v1.0
#拷贝jar包
COPY target/*.jar /demo-service.jar
#暴露端口
EXPOSE 8080
#健康检查
HEALTHCHECK --interval=30s --timeout=3s \
 CMD curl -fs http://localhost:8080 || exit 1
#ENTRYPOINT ["java","-jar","/demo-service.jar"]
ENTRYPOINT ["sh","-c","java -jar  -Xms100m -Xmx100m /demo-service.jar --server.port=8080"]

3、构建镜像
docker build -t springboot:v1.0 .

4、运⾏业务镜像测试
docker run -itd -p 8080:8080 --name springboot springboot:v2.0

5、访问应⽤
curl http://localhost:8080

5 dockerfile多阶段构建

5.1 什么是多阶段构建

Docker 多阶段构建(Multi-stage builds)是⼀种优化 Docker 镜像构建过程的⽅法,它允许你在⼀个 Dockerfile 中定义多个构建阶段。在实际镜像的构建过程,我们可能会碰到编译代码和运⾏代码需要不同的依赖(例如:Nodejs在编译阶段需要npm,运⾏阶段仅需要Nginx)。传统的做法是在⼀个 Dockerfile 中完成所有操作,但这样会导致镜像变得臃肿且包含很多不必要的组件。

⽽多阶段构建通过在COPY --from 语句,我们可以在阶段之间传递⽂件或者数据。

Docker v17.05 开始支持多阶段构建 (multistage builds)。

只构建某一阶段的镜像
我们可以使用as 来为某一阶段命名,例如
FROM golang:alpine as builder

例如当我们只想构建builder 阶段的镜像时,增加 --target=builder 参数即可
$ docker build --target builder -t username/imagename:tag .

5.2 多阶段构建优势

下⾯是⼀个简单的Node.js应⽤的Dockerfile,该Dockerfile包含了两个阶段:

1、构建阶段:使⽤ Node.js alpine 镜像作为编译环境,安装依赖,编译应⽤。

2、运⾏阶段:使⽤ nginx 稳定版 alpine 镜像作为运⾏环境,将 build阶段编译好的 dist ⽬录复制⾄Nginx站点路径。

# 第⼀阶段:编译nodejs 
FROM node:alpine AS build 
WORKDIR /app 
COPY package.json . 
RUN npm install 
COPY . . 
RUN npm run build 
# 第⼆阶段:运⾏应⽤
FROM nginx:stable-alpine 
COPY --from=build /app/dist /usr/share/nginx/html

这样,最终的Nginx 镜像只包含编译结果,⽽不会将 Node.js 环境和源代码都复制进来,⼤⼤减⼩了镜像⼤⼩。同时也实现了编译环境和运⾏环境的隔离。

5.3 Golang多阶段构建

构建⼀个运⾏Go语⾔程序的镜像。我们需要先编译 Go 代码,然后将编译后的可执⾏⽂件放到⼀个轻量级的运⾏环境中。

1、编写go代码
cat main.go 
package main 
import "fmt" 
func main() { 
fmt.Println("Hello, qingchen!") 
} 

2、编写Dockerfile
#第一阶段,编译代码
#基础镜像
FROM hub.atomgit.com/amd64/golang:1.19.13 AS build
#指定工作目录
WORKDIR /app
#拷贝代码
COPY ./main.go .
#编译main.go为myapp
RUN go build -o myapp main.go
#####################################
#第二阶段,运行go项目
FROM alpine:latest
#将构建阶段/app下的项目拷贝到该容器的/app目录
COPY --from=build /app/myapp /app/myapp
#运行项目
ENTRYPOINT ["sh","-c","/app/myapp"]

3、构建镜像
docker build -t golang_hello:v1.0 .

4、运⾏镜像 
docker run -it golang_hello:v1.0

5、检查编译环境⼤⼩和运⾏环境镜像⼤⼩

七、docker镜像构建_tomcat_11

5.4 Java多阶段构建

1、下载代码

2、编写Dockerfile
2.1、生成基础jDK镜像
cat dockerfile
#指定基础镜像
FROM hub.atomgit.com/library/centos:7
#指定镜像的作者
MAINTAINER qingchen
#设置环境变量
ENV JDK_VERSION=jdk-8u351-linux-x64
#拷贝JDK安装包
COPY ./${JDK_VERSION}.rpm .
#安装清理
RUN rpm -ivh ${JDK_VERSION}.rpm && \
rm -f ${JDK_VERSION}.rpm

docker build -t jdk1.8:v1.0 .

2.2、JAVA分阶段构建
cat dockerfile
#第一阶段基础构建
#指定基础镜像
FROM jdk1.8:v1.0 AS build_base
#指定镜像的作者
MAINTAINER qingchen
#拷贝安装maven
ADD ./apache-maven-3.6.2-bin.tar.gz /app
COPY ./settings.xml /app/apache-maven-3.6.2-bin/conf/
#做软连接
RUN ln -s /app/apache-maven-3.6.2-bin/bin/mvn /usr/bin/mvn
#上传代码包
ADD ./springboot-helloworld-docker.tar.gz /
#配置JAVA_HOME
ENV JAVA_HOME=/usr/java/jdk1.8.0_351-amd64
#编译打包
RUN cd /springboot-helloworld && \
    mvn package
########################################
#第二阶段构建
FROM jdk1.8:v1.0
#拷贝编译后的jar包
COPY --from=build_base /springboot-helloworld/target/*.jar /demo-service.jar
#暴露端口
EXPOSE 8080
#执行命令
ENTRYPOINT ["sh","-c","java -jar /demo-service.jar --server.port=8080"]

构建镜像
docker build -t springboot:v3.0 .

3、启动并测试容器 
curl http://localhost:8080

检查此前构建的java业务镜像、以及现在多阶段构建的java业务镜像

七、docker镜像构建_5e_12

七、docker镜像构建_centos_13

6 docker多架构

6.1 多架构构建镜像

多架构,指的并⾮是不同的操作系统,⽽指的是不同的CPU架构。我们可以根据不同的CPU架构,构建Docker镜像。最常⻅的架构有:

AMD64:Intel和AMD的64位CPU

ARM64:MacOS M1芯⽚使⽤的架构

七、docker镜像构建_5e_14

如果你使⽤的是Mac的M1芯⽚,通过Docker运⾏⼀个容器,并不会有任何问题,这是因为Docker会根据当前的CPU架构选择对应的镜像架构。同时也不需要进⾏额外的命令修改,就可以在M1芯⽚上直接运⾏Docker。

6.2 构建⼯具Buildx

使⽤buildx⼯具多架构镜像,其原理是,拉取⼀个镜像运⾏为容器,⽽后在容器中对不同的CPU架构进⾏分别构建,好处就是⽆需对Dockerfile进⾏任何更改,仅需要传递⼀个 --platform 的标志给构建命令,指定要构建的架构;

1、通过以下命令为 linux/arm/v7 平台构建镜像

docker buildx build --platform=linux/arm/v7 -t springboot:v1.0 .  

2、默认构建驱动程序并不⽀持多平台构建,需要切到到另⼀个构建器,他⽀持并发构建多平台的驱动程序。

# 创建⼀个docker-container类型的构建器

docker buildx create --driver=docker-container --name=container

列出⽬前可⽤的构建器

七、docker镜像构建_tomcat_15

新构建器container的状态是⾮活动的。这是因为还没有开始使⽤它

6.3 Buildx构建实践

仿真构建指的是在⼀种架构(通常是X86)的机器上,模拟另⼀种架构(例ARM)的运⾏环境,然后在该环境中编译程序。这种编译出的程序可以在⽬标架构上直接运⾏。

七、docker镜像构建_centos_16

1、使⽤buildx将springboot镜像构建⽀持多平台,额外需要添加如下两个选项
--builder=container # 选择哪个构建器 
--platform=linux/amd64,linux/arm/v7,linux/arm64/v8 # ⼀次构建多个架构 

2、准备dockerfile⽂件,⽽后执⾏构建命令 
cat Dockerfile
FROM jdk1.8:v1.0
#拷贝jar包
COPY target/*.jar /demo-service.jar
#暴露端口
EXPOSE 8080
#健康检查
HEALTHCHECK --interval=30s --timeout=3s \
 CMD curl -fs http://localhost:8080 || exit 1
#ENTRYPOINT ["java","-jar","/demo-service.jar"]
ENTRYPOINT ["sh","-c","java -jar  -Xms100m -Xmx100m /demo-service.jar --server.port=8080"]

docker buildx build \
--push \
--builder=container \
--platform=linux/amd64,linux/arm/v7,linux/arm64/v8 \
-t springboot:v4.0 .