docker之构建自己的镜像

通过docker之初见docker之基石—镜像中体验了通过 docker 来使用tomcatmysql,并了解了镜像的构成,那么有个问题,我们以前都是通过官网去下载安装包==>解压到指定目录==>修改配置文件==>启动使用,现在使用 docker 只要pull一下镜像,run一下就可以启动,如此简单,那么这个镜像包的Dockerfile是怎么定义?

官方Dockerfile

首先来看下 docker 的官方镜像的代码仓库https://github.com/docker-library/official-images,在这个仓库里有的 library 目录里找到一个 mysql 的文件,里面的内容是这样的。

# this file is generated via https://github.com/docker-library/mysql/blob/ff627942605ce08a32fa527993337df0e9856760/generate-stackbrew-library.sh

Maintainers: Tianon Gravi <admwiggin@gmail.com> (@tianon),
             Joseph Ferguson <yosifkit@gmail.com> (@yosifkit)
GitRepo: https://github.com/docker-library/mysql.git

Tags: 8.0.20, 8.0, 8, latest
GitCommit: bc6e37a2bed792b1c4fc6ab1ec3ce316e6a5f061
Directory: 8.0

Tags: 5.7.30, 5.7, 5
GitCommit: bc6e37a2bed792b1c4fc6ab1ec3ce316e6a5f061
Directory: 5.7

Tags: 5.6.48, 5.6
GitCommit: bc6e37a2bed792b1c4fc6ab1ec3ce316e6a5f061
Directory: 5.6

5行的代码告诉我们, mysql 镜像仓库的代码在 https://github.com/docker-library/mysql.git ,打开看下发现有好几个版本,这里打开5.7 的版本来看下。

发现有一个叫Dockerfile的文件,应该就是生成 mysql 镜像的配置了,如果拿到这一份配置,是不是自己也可以生成一个镜像呢?

按照这个想法,来尝试一下。

# 创建一个空白目录,并进入
mkdir create-mysql-image && cd create-mysql-image
# 通过vi将 mysql 5.7 的 Dockerfile 内容保存到本地,并将文件名保存为 Dockerfile
vi Dockerfile
# 使用 docker build 命令进行镜像构建
# -t 指定镜像的名称为mysql,并自定tag为custom
# 需要注意的是最后一个点,是在指定上下文目录,docker build 命令会将该目录下的内容打包交给 Docker 引擎以帮助构建镜像。
docker build -t mysql:custom .

等待了几分钟发现报错了,报错的内容为:

Step 14/18 : COPY docker-entrypoint.sh /usr/local/bin/
COPY failed: stat /var/lib/docker/tmp/docker-builder874622285/docker-entrypoint.sh: no such file or directory

脚本执行的过程需要复制一个名为docker-entrypoint.sh的文件,所以将 github 上的[docker-entrypoint.sh](https://github.com/docker-library/mysql/blob/master/5.7/docker-entrypoint.sh)也保存下来,然后执行docker build -t mysql:custom .,等待打包结束。

# 查看是否存在  mysql:custom
docker image ls
#REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
#mysql               custom              129011b1e809        14 seconds ago      448MB
#debian              buster-slim         108d75da320f        2 weeks ago         69.2MB

果然有了。

使用容器创建镜像

# 创建一个nginx 容器
[vagrant@nexus3 ~]$ docker run -d --name my-nginx -p 3000:80 nginx
5535e66541d0facb4475717f1788c3839ebae2a26f9f394eb8cf7033ea0944fd
# 访问容器
[vagrant@nexus3 ~]$ curl localhost:3000
# <!DOCTYPE html>
# <html>
# <head>
# <title>Welcome to nginx!</title>
# <style>
#     body {
#             width: 35em;
#             margin: 0 auto;
#             font-family: Tahoma, Verdana, Arial, sans-serif;
#             }
# </style>
# </head>
# <body>
# <h1>Welcome to nginx!</h1>
# <p>If you see this page, the nginx web server is successfully installed and
#         working. Further configuration is required.</p>
# 
# <p>For online documentation and support please refer to
# <a href="http://nginx.org/">nginx.org</a>.<br/>
#         Commercial support is available at
# <a href="http://nginx.com/">nginx.com</a>.</p>
# 
# <p><em>Thank you for using nginx.</em></p>
# </body>
# </html>



# 进入容器
[vagrant@nexus3 ~]$ docker exec -it my-nginx /bin/bash
# 修改 nginx 首页展示内容
root@5535e66541d0:/# cd /usr/share/nginx/html/
root@5535e66541d0:/usr/share/nginx/html# ls
# 50x.html  index.html
root@5535e66541d0:/usr/share/nginx/html# echo "hello docker!" > index.html
root@5535e66541d0:/usr/share/nginx/html# exit
# exit
# 重新访问首页,查看是否修改成功
[vagrant@nexus3 ~]$ curl localhost:3000
# hello docker!

# 使用 docker commit 根据容器 my-nginx 创建镜像 nginx:v2
[vagrant@nexus3 ~]$ docker commit --author "xingmu" --message "修改nginx默认首页" my-nginx nginx:v2
#sha256:deafd57279f0b4d1bd89e352469833e81fc40fbe3391f5a8cfdbeb065192251f

#查看镜像列表,是否创建成功
[vagrant@nexus3 ~]$ docker image ls
#REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
#nginx               v2                  deafd57279f0        5 seconds ago       127MB
#custom-image        1.0                 eae6faff977a        27 minutes ago      528MB
#mysql               custom              129011b1e809        18 hours ago        448MB
#mariadb             latest              ac9c11a18222        2 days ago          357MB
#tomcat              latest              1b6b1fe7261e        2 weeks ago         647MB
#openjdk             8                   1077d23b5882        2 weeks ago         510MB
#nginx               latest              9beeba249f3e        2 weeks ago         127MB

# 查看 nginx:v2 的镜像层历史
[vagrant@nexus3 ~]$ docker history nginx:v2
#IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
#deafd57279f0        39 seconds ago      nginx -g daemon off;                            119B                修改nginx默认首页
#9beeba249f3e        2 weeks ago         /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B                  
#<missing>           2 weeks ago         /bin/sh -c #(nop)  STOPSIGNAL SIGTERM           0B                  
#<missing>           2 weeks ago         /bin/sh -c #(nop)  EXPOSE 80                    0B                  
#<missing>           2 weeks ago         /bin/sh -c ln -sf /dev/stdout /var/log/nginx… # ...

# 使用 nginx:v2 创建一个容器 my-nginx02
[vagrant@nexus3 ~]$ docker run -d --name my-nginx02 -p 3001:80 nginx:v2 
# 3e9e7598b72cd8367dc18316967d0dec0ad57b00b15a82f08fdf7b65b1e3dd65

# 访问容器 my-nginx02 服务
[vagrant@nexus3 ~]$ curl localhost:3001
# hello docker!

使用 docker commit 命令虽然可以比较直观的帮助理解镜像分层存储的概念,但是实际环境中并不会这样使用。

如果仔细观察之前的 docker diff webserver 的结果,你会发现除了真正想要修改的 /usr/share/nginx/html/index.html 文件外,由于命令的执行,还有很多文件被改动或添加了。这还仅仅是最简单的操作,如果是安装软件包、编译构建,那会有大量的无关内容被添加进来,如果不小心清理,将会导致镜像极为臃肿。

Dockerfile

使用 docker commit 虽然可以通过对容器的修改来创建镜像,但是除了制作镜像的人知道执行过什么命令、怎么生成的镜像,别人根本无从得知。而且,即使是这个制作镜像的人,过一段时间后也无法记清具体的操作。所以使用这种方式生成的镜像维护起来是非常痛苦的。

如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。

Dockerfile 是一个文本文件,其内包含了一条条的 指令(Instruction),每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。也就是说,如果我们熟悉Dockerfile的一个编写语法,也可以定制自己的镜像。

dockerfile 语法

FROM 指定基础镜像

所谓定制镜像,那一定是以一个镜像为基础,在其上进行定制。 FROM 就是指定 基础镜像的,因此一个 DockerfileFROM 是必备的指令,并且必须是第一条指令

Docker Hub 上有非常多的高质量的官方镜像,其中还提供了一些更为基础的操作系统镜像,如 ubuntudebiancentosfedoraalpine 等,这些操作系统的软件库为我们提供了更广阔的扩展空间。

除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。

FROM scratch
...

如果你以 scratch 为基础镜像的话,意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见,比如 swarmetcd。对于 Linux 下静态编译的程序来说,并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接 FROM scratch 会让镜像体积更加小巧。使用 Go 语言 开发的应用很多会使用这种方式来制作镜像,这也是为什么有人认为 Go 是特别适合容器微服务架构的语言的原因之一。

RUN 执行命令

RUN 指令是用来执行命令行命令的。由于命令行的强大能力,RUN 指令在定制镜像时是最常用的指令之一。其格式有两种:

  • shell 格式:RUN <命令>,就像直接在命令行中输入的命令一样。
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
  • exec 格式:RUN ["可执行文件", "参数1", "参数2"],这更像是函数调用中的格式。

之前说过,Dockerfile 中每一个指令都会建立一层,RUN 也不例外。指令执行结束后,commit 这一层的修改,构成新的镜像。需要注意的是 Union FS 是有最大层数限制的,比如 AUFS,曾经是最大不得超过 42 层,现在是不得超过 127 层。

更多命令,请参看这里https://yeasy.gitbook.io/docker_practice/image/dockerfile

定义自己的镜像

  1. 创建一个Spring Boot项目,并写一个 controller

    @RestController
    public class DockerController {
        @GetMapping("/dockerfile")
        @ResponseBody
        String dockerfile() {
            return "hello docker" ;
        }
    }
    
  2. mvn clean package打成一个jar包

    在target下找到dockerfile-demo-0.0.1-SNAPSHOT.jar

  3. 在 docker 环境中创建一个空目录dockerfile-demo

  4. 将第二步中的jar复制到上一步创建的目录

  5. 创建Dockerfile文件,加入如下内容

    # 基础镜像
    FROM openjdk:8
    # 设置镜像元数据
    LABEL name="dockerfile-demo" vaersion="1.0" author="xingmu"
    # 复制 jar 包到镜像,并重命名为 dockerfile-image.jar
    COPY dockerfile-demo-0.0.1-SNAPSHOT.jar dockerfile-image.jar
    # 启动命令
    CMD java -jar dockerfile-image.jar
    
  6. 基于 Dockerfile 构建镜像

    docker build -t custom-image:1.0 .
    docker image ls
    #REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    #custom-image        1.0                 eae6faff977a        9 minutes ago       528MB
    
    
  7. 基于上一步构建的镜像,创建container

    docker run -d --name custom-image-c1 -p 8081:8080 custom-image:1.0
    docker ps
    #CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
    #0bfd8ad50b46        custom-image:1.0    "/bin/sh -c 'java -j…"   10 seconds ago      Up 9 seconds        0.0.0.0:8081->8080/tcp   custom-image-c1
    
    
  8. 查看启动日志

    docker logs custom-image-c1 
    
      .   ____          _            __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::        (v2.2.0.RELEASE)
    
    2020-05-31 09:54:34.989  INFO 6 --- [           main] c.g.d.DockerfileDemoApplication          : Starting DockerfileDemoApplication v0.0.1-SNAPSHOT on 0bfd8ad50b46 with PID 6 (/dockerfile-image.jar started by root in /)
    2020-05-31 09:54:34.996  INFO 6 --- [           main] c.g.d.DockerfileDemoApplication          : No active profile set, falling back to default profiles: default
    
    
  9. 访问镜像服务

    curl localhost:8081/dockerfile
    # hello docker
    

发布镜像

将镜像发布到 docker hub

  1. 首先要拥有一个 docker hub 的账号,如果没有就到 https://hub.docker.com/ 去注册一个

  2. 在本地登录 docker hub

    docker login
    #Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
    
    # 输入在 hub.docker.com 上注册的用户名和密码
    Username: xingmu2020
    Password: 
    #WARNING! Your password will be stored unencrypted in /home/vagrant/.docker/config.json.
    #Configure a credential helper to remove this warning. See
    #https://docs.docker.com/engine/reference/commandline/login/#credentials-store
    
    #Login Succeeded
    
  3. 将镜像上传到 docker hub

    docker hub 对上传镜像的格式是有要求的,<docker hub 账号>/仓库名称:tag,需要对本地镜像打 tag。

    # 给镜像打tag
    docker tag custom-image:1.0 xingmu2020/springboot-docker-demo:1.0
    # 上传镜像
    docker push xingmu2020/springboot-docker-demo:1.0
    

    docker hub 在国外,速度感人,需要多等几分钟。

    push完成之后,在 https://hub.docker.com/repositories 应该就可以看到自己制作的镜像了。

    在这里插入图片描述

这时候,其他人也可以通过 docker pull xingmu2020/springboot-docker-demo:1.0来下载这个镜像并使用了。

将镜像发布到阿里云 docker 仓库

aliyun 容器镜像服务地址 https://cr.console.aliyun.com/cn-hangzhou/instances/repositories

  1. 登录到阿里云 docker 仓库,这里具体登录说明https://cr.console.aliyun.com/cn-hangzhou/instances/credentials

    docker login --username=username@mail.com registry.cn-hangzhou.aliyuncs.com
    # 输入在上面的地址中设置的固定密码
    Password: 
    #WARNING! Your password will be stored unencrypted in #/home/vagrant/.docker/config.json.
    #Configure a credential helper to remove this warning. See
    #https://docs.docker.com/engine/reference/commandline/login/#credentials-store
    
    #Login Succeeded
    
  2. 创建命名空间

    到这里https://cr.console.aliyun.com/cn-hangzhou/instances/namespaces 去创建一个自己的命名空间,我这里创建的是xingmu2020

  3. 给镜像打 tag

    docker tag custom-image:1.0 registry.cn-hangzhou.aliyuncs.com/xingmu2020/springboot-docker-demo:aliyun1.0
    
  4. 推送镜像到 阿里云 镜像服务器

    docker push registry.cn-hangzhou.aliyuncs.com/xingmu2020/springboot-docker-demo:aliyun1.0 
    

推送完成,就可以在 https://cr.console.aliyun.com/cn-hangzhou/instances/repositories 看到刚才推送的景象了。这时候,其他人也可以通过 docker pull registry.cn-hangzhou.aliyuncs.com/xingmu2020/springboot-docker-demo:aliyun1.0来下载这个镜像并使用了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值