docker容器不同场景下构建

宗旨:所有容器尽可能的精简,且最小化对环境依赖。

场景一:java运行时基础镜像(运行环境)

此场景只需要java运行环境,因为只需要运行可执行jar文件,所以只需要基于alpine镜像
加入jdk中的jre即可。
编写Dockerfile如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 基于业界的基础包
From alpine:3.9
# 设置默认编码格式
ENV LANG C.UTF-8
# 定义java的环境变量
ENV JAVA_HOME /usr/lib/jvm/default-jvm
ENV JAVA_VERSION 8u212
ENV JAVA_ALPINE_VERSION 8.212.04-r0
# 复制jce包
COPY jce_policy-8.zip /tmp/jce_policy-8.zip
# 使用apk add 下载相关软件(apk 是alpine内置软件包管理器)
RUN apk add --no-cache openjdk8-jre="$JAVA_ALPINE_VERSION" \
&& mkdir $JAVA_HOME/lib/security \
&& unzip -oj -d $JAVA_HOME/lib/security /tmp/jce_policy-8.zip \*/\*.jar \
&& rm /tmp/jce_policy-8.zip
CMD ["java", "-version"]

最后执行docker构建命令:
docker build --build-arg http_proxy=$http_proxy -t moduleName/jre8-alpine:v1 .
注意事项:

  1. 参照docker hub官网中写法,但要最小化,所以去掉不必要的命令,如校验
  2. 增加加解密key长度限制的补丁(防止在加解密的时候报 java.security.InvalidKeyException)
    由于使用代理无法直接从官网下载jce_policy-8.zip,所以可以在宿主机上预先下载好,再在容器内使用【附件:jce_policy-8.zip】
  3. 若执行失败,可以启动一个最小化alpine并进入alpine测试
  4. 构建时需要添加代理,以使得可以正确下载jre文件
  5. 构建命令中注意最后一个点’.’代表在当前路径下查找dockerfile文件

    场景二:maven编译时镜像(编译环境)

    此场景是将我们的java文件,编译并打包,共用到两个工具jdk和maven
    同样我们基于alpine进行构建
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    FROM alpine:3.9
    # 增加java和maven的环境变量
    ENV LANG C.UTF-8
    ENV JAVA_HOME /usr/lib/jvm/java-1.8-openjdk
    ENV PATH $PATH:$JAVA_HOME/jre/bin:$JAVA_HOME/bin
    ENV JAVA_VERSION 8u212
    ENV JAVA_ALPINE_VERSION 8.212.04-r0
    ENV MAVEN_HOME /usr/share/maven

    ARG MAVEN_VERSION=3.6.1
    # 用来校验压缩文件的完整性
    ARG SHA=b4880fb7a3d81edd190a029440cdf17f308621af68475a4fe976296e71ff4a4b546dd6d8a58aaafba334d309cc11e638c52808a4b0e818fc0fd544226d952544
    ARG BASE_URL=https://apache.osuosl.org/maven/maven-3/${MAVEN_VERSION}/binaries
    # 安装jdk和maven安装包以及一些辅助软件
    RUN apk add --no-cache curl tar bash procps openjdk8="$JAVA_ALPINE_VERSION" \
    && curl -fsSL -o /tmp/apache-maven.tar.gz ${BASE_URL}/apache-maven-${MAVEN_VERSION}-bin.tar.gz \
    && echo "${SHA} /tmp/apache-maven.tar.gz" | sha512sum -c - \
    && mkdir -p $MAVEN_HOME \
    && tar -xzf /tmp/apache-maven.tar.gz -C $MAVEN_HOME --strip-components=1 \
    && rm -f /tmp/apache-maven.tar.gz \
    && ln -s $MAVEN_HOME/bin/mvn /usr/bin/mvn

    COPY settings.xml $MAVEN_HOME/conf/settings.xml
    ENTRYPOINT ["mvn"]
    CMD ["-v"]
    最后执行docker构建命令:
    docker build --build-arg http_proxy=$http_proxy --build-arg https_proxy=$https_proxy -t test/maven-jdk8-alpine:v1 .

场景三:搭建应用镜像(真正运行的server环境)

此镜像主要是我们写程序后真正的运行环境
为了减少环境的依赖,应该分阶段打包:

阶段一:依赖maven编译镜像构建,复制源代码到镜像中,并将源文件编译打包成可执行文件

阶段二:依赖java运行时基础镜像构建,将阶段一种打包好的可执行jar包复制到镜像中运行。

以上分阶段可以使得最后我们需要的镜像最小化,没有maven和jdk,只是基于alpine的jre环境。
另外编译过程放在了容器中,减少了对于宿主机环境的依赖。

1
2
3
4
5
6
7
8
9
10
# Builder image
FROM huawei/maven-jdk8-alpine:v1 AS builder
COPY . /{imagesrc-path}
WORKDIR /${imagesrc-path}
RUN mvn clean package
# Runtime image
FROM huawei/jre8-alpine:v1
COPY --from=builder /${imagesrc-path}/service/target/{module-name}.jar {module-name}.jar
CMD java -jar /{module-name}.jar --spring.profiles.active=test
EXPOSE 8078

最后编译镜像 (组织(项目名)/模块:版本):docker build -t {project-name}/{module-name}:{version} .
注意事项:
`. 使用 COPY –from=builder 引用上一个镜像,就如同此镜像的宿主机,其中builder为上一个镜像我们取名(若不取名可以使用–from=0这种序号来表示,但不推荐)。
2. 对外暴露端口
3. 复制文件时注意路径(不是workdir)
4. {imagesrc-path}是指定当前镜像路径,若没有会创建如/applogin/src

上传和运行镜像

上传第三方镜像到docker仓库 wiki参考

1
2
3
4
#先给镜像打上标签:
docker tag {project-name}/{module-name} {repository}/{project-name}/{module-name}:{version}
#上传
docker push {repository}/{project-name}/{module-name}:{version}

对于我们构建好的应用镜像,我们需要运行,并使用端口代理给外部访问
运行镜像:
docker run -p 8078:8078 –name {ServerName} {project-name}/{module-name}
另外可以在run命令中加入cmd命令覆盖原来的参数(主要可以设置不同的参数如spring.profiles.active)
注意:pull镜像和使用镜像时无需待带ip:52001前缀,会自动去掉

关于Dockerfile中的指令:

  1. ENV和ARG的区别:ARG可以作为dockerfile文件中的变量,ENV作为镜像运行时的环境变量,可以在RUN时使用
  2. CMD和ENTRYPOINT区别,CMD为默认命令,如果构建时带命令或者有ENTRYPOINT命令则会被覆盖,ENTYRPOINT若配置,则是真正默认入口命令,若没有带参数则将CMD[“arg”]中arg 为参数。

    一般使用方法为:用entrypoint的中括号形式作为docker 容器启动以后的默认执行命令,里面放的是不变的部分,可变部分比如命令参数可以使用cmd的形式提供默认版本,也就是run里面没有任何参数时使用的默认参数。如果我们想用默认参数,就直接run,否则想用其他参数,就run 里面加参数。

  3. COPY和ADD区别 ,ADD|COPY 两者src都是相对路径,但ADD中可以填写url远程地址,不能用于多阶段构建,而COPY支持多阶段构建,但不支持url。一般推荐使用COPY,涉及到远程复制文件,建议使用RUN+wget,curl的方式。