docker构建镜像

2020-09-28

1 What & Why

What: 什么是构建docker镜像?

构建docker镜像在现有镜像的基础上,修改或添加个人的功能后,重新打包成新镜像的过程

Why: 为什么要构建docker镜像?

docker镜像方便部署及分享他人

2 Hello World

2.1 目标

  1. 利用现有镜像ubuntu构建新镜像
  2. 镜像的功能是利用ubuntu的echo命令打印Hello world

2.2 创建文件夹

mkdir demo01-helloworld
cd demo01-helloworld

2.3 创建配置文件

Docker以文件Dockerfile作为配置文件,内容如下

Dockerfile

FROM ubuntu:latest

CMD ["/bin/echo", "Hello world!"]

以上内容非常简单

  • FROM用来配置基础镜像,这里以ubuntu的最新版本的镜像作为基础镜像
  • CMD表示镜像中执行的命令,这里等同于执行命令/bin/echo "Hello World!"
    • 当前的格式为Exec格式
    • 后面会介绍shell格式

2.4 构建镜像

命令

docker image build . -t demo01-helloworld:0.0.1
  • .表示当前文件夹里的所有文件

  • -t等同于--tag,作用是给镜像打标签,这里的标签名为demo01-helloworld

  • :后是镜像的版本号,如果省略则默认为latest

构建过程如下,当打印Successfully tagged demo01-helloworld:0.0.1表明镜像构建成功

$ docker image build . -t demo01-helloworld
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM ubuntu:latest
 ---> 4e2eef94cd6b
Step 2/2 : CMD ["/bin/echo", "Hello world!"]
 ---> Running in 581995f3af46
Removing intermediate container 581995f3af46
 ---> afa0f6e8fc94
Successfully built afa0f6e8fc94
Successfully tagged demo01-helloworld:0.0.1

可以用命令docker image ls查询所有镜像,再次确认已经构建完成

$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
demo01-helloworld   0.0.1               afa0f6e8fc94        19 seconds ago      73.9MB

运行镜像,先生成容器,再启动容器

$ docker container run demo01-helloworld:0.0.1
Hello world!

docker启动时先判断有没有该容器,如果不存在则通过镜像创建相应的容器,然后执行容器

2.5 注意

需要说明的是CMD可以在构造镜像的时候不指定,启动容器的时候执行。如果启动时指定了命令,则CMD中指定的命令将不会执行,即被覆盖,现象如下。你看懂了吗?

$ docker container run demo01-helloworld:0.0.1 /bin/echo "Hello world! v2"
Hello world! v2

3 java应用

3.1 目标

  1. 利用现有镜像openjdk构建新镜像
  2. 镜像的功能是运行java程序打印Hello java

3.2 创建文件夹

mkdir demo02-hellojava
cd demo02-java

3.3 创建java工程

选择你喜欢的方式创建一个maven工程,可以从通过网页下载模板,可以利用eclipse和idea等等

这里采用mvn命令的方式创建

mvn archetype:generate -DgroupId=org.zwx.hellojava -DartifactId=demo02-hellojava -DinteractiveMode=false

结果如下

$ mvn archetype:generate -DgroupId=org.zwx.hellojava -DartifactId=demo02-hellojava -DinteractiveMode=false
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------< org.apache.maven:standalone-pom >-------------------
[INFO] Building Maven Stub Project (No POM) 1
[INFO] --------------------------------[ pom ]---------------------------------
[INFO] ...省略一些内容
[INFO] Parameter: basedir, Value: /Users/zhouweixin/docker-demos
[INFO] Parameter: package, Value: org.zwx.hellojava
[INFO] Parameter: groupId, Value: org.zwx.hellojava
[INFO] Parameter: artifactId, Value: demo02-hellojava
[INFO] Parameter: packageName, Value: org.zwx.hellojava
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] project created from Old (1.x) Archetype in dir: /Users/zhouweixin/docker-demos/demo02-hellojava
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  16.557 s
[INFO] Finished at: 2020-09-28T17:55:09+08:00
[INFO] ------------------------------------------------------------------------

文件目录

.
├── pom.xml
└── src
    ├── main
    │   └── java
    │       └── org
    │           └── zwx
    │               └── hellojava
    │                   └── App.java
    └── test
        └── java
            └── org
                └── zwx
                    └── hellojava
                        └── AppTest.java

3.4 编译执行

在打包之前先确定java应用可以正常执行

首先,修改文件src/main/java/org/zwx/hellojava/App.java

package org.zwx.hellojava;

/**
 * Hello world!
 *
 */
public class App
{
    public static void main( String[] args )
    {
        System.out.println( "Hello java!" );
    }
}

然后,用mvn命令编译打包

$ mvn package
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------< org.zwx.hellojava:demo02-hellojava >-----------------
[INFO] Building demo02-hellojava 1.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] ...省略一些内容
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ demo02-hellojava ---
[INFO] Building jar: /Users/zhouweixin/docker-demos/demo02-hellojava/target/demo02-hellojava-1.0-SNAPSHOT.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.531 s
[INFO] Finished at: 2020-09-28T17:59:40+08:00
[INFO] ------------------------------------------------------------------------

文件目录

.
├── pom.xml
├── src
│   └── ...省略一些内容
└── target
    ├── demo02-hellojava-1.0-SNAPSHOT.jar
    └── ...省略一些内容

当你执行完命令mvn package后,首先会编译生成一些class文件,然后打包成demo02-hellojava-1.0-SNAPSHOT.jar,生成的文件都在目录target下

该jar文件是执行文件,具体执行命令如下

$ java -cp target/demo02-hellojava-1.0-SNAPSHOT.jar org.zwx.hellojava.App
Hello java!

3.5 拉取基础镜像

如前文所述构建镜像需要一个基础镜像,基础镜像也可以不提前拉取,构建的时候如果不存在也会自动拉取

该例子中要想启动java应用,你知道需要哪个环境吗?

你应该是猜对了,仅仅需要java的运行时环境(jre)

首先到hub.docker.com上检索jre的相关tag,这里我们选择的是8u265-jre

二话不说,先拉取镜像(也可以不提前拉取)

$ docker pull openjdk:8u265-jre
8u265-jre: Pulling from library/openjdk
57df1a1f1ad8: Pull complete
71e126169501: Pull complete
1af28a55c3f3: Pull complete
a9777c2d5c29: Pull complete
9248106993db: Pull complete
1f74ab5b5b3e: Pull complete
Digest: sha256:e98dece4606dc1ec47c0c9ab6aa43931577232a5b7d6fd46f3ead7377727b412
Status: Downloaded newer image for openjdk:8u265-jre
docker.io/library/openjdk:8u265-jre

用交互的方式运行该镜像并确定java的版本

$ docker container run -it openjdk:8u265-jre
root@0687c67dccd0:/# java -version
openjdk version "1.8.0_265"
OpenJDK Runtime Environment (build 1.8.0_265-b01)
OpenJDK 64-Bit Server VM (build 25.265-b01, mixed mode)

参数说明

  • -it-i-t的缩写
  • -i全称是--interactive,即交互模式,可以正常的输入输出
  • -t是一个伪TTY,即伪终端

3.6 构建镜像

创建配置文件Dockerfile

FROM openjdk:8u265-jre

COPY target/demo02-hellojava-1.0-SNAPSHOT.jar /usr/src/demo02-hellojava-1.0-SNAPSHOT.jar

CMD java -cp /usr/src/demo02-hellojava-1.0-SNAPSHOT.jar org.zwx.hellojava.App

参数说明

  • COPY命令用于将本地文件拷贝到基础镜像中,并且这个基础镜像中有java运行时环境,两者结合满足正常运行程序
    • 第一个参数为本地文件目录
    • 第二个参数为基础镜像中的目录
  • CMD命令表示在基础镜像中执行的命令(可以不写数组的形式)

执行镜像构建命令

$ docker image build . -t demo02-hellojava:0.0.1
Sending build context to Docker daemon  38.91kB
Step 1/3 : FROM openjdk:8u265-jre
 ---> d9d1d3243082
Step 2/3 : COPY target/demo02-hellojava-1.0-SNAPSHOT.jar /usr/src/demo02-hellojava-1.0-SNAPSHOT.jar
 ---> Using cache
 ---> 6c34d345bb51
Step 3/3 : CMD java -cp /usr/src/demo02-hellojava-1.0-SNAPSHOT.jar org.zwx.hellojava.App
 ---> Running in 0d9a33ea0ae1
Removing intermediate container 0d9a33ea0ae1
 ---> fc3cd9ee5218
Successfully built fc3cd9ee5218
Successfully tagged demo02-hellojava:0.0.1

启动

$ docker container run demo02-hellojava:0.0.1
Hello java!

4 Dockfile中的命令

命令 功能
FROM 指定基础镜像
COPY 复制文件或文件夹
ENV 设置环境变量
RUN 执行一个命令,可以写多个,通常用于安装软件包
CMD 执行一个命令,只有一个被执行,可被docker run后面的命令所覆盖,即如果命令行中有该命令,CMD中的将不会执行
ENTRYPOINT 配置容器启动时的命令,一定会执行
EXPOSE 暴露的端口号

参考