Docker-实战笔记应用容器化

38次阅读

共计 5304 个字符,预计需要花费 14 分钟才能阅读完成。

应用的容器化

Docker 的核心思想就是如何将应用整合到容器中,并且能在容器中实际运行。将应用整合到容器中并且运行起来的这个过程,称为“容器化(Containerizing)”,有时候也叫“Docker 化(Dockerizing)”。

应用容器化主要分为以下几个步骤:

  • 编写应用代码
  • 创建一个 Dockerfile,其中包括当前应用的描述、依赖以及该如何运行这个应用
  • 对该 Dockerfile 执行 docker image build 命令
  • 等待 Docker 将应用程序构建到整个 Docker 镜像中

一旦应用容器化完成,就能够以镜像的形式交付并以容器的方式运行了。

######### 应用容器化的基本命令 ########
#基于 Dockerfile 文件构建镜像 - t 表示为镜像打标签 - f 表示为 Dockerfile 指定路径和名称 - f 表示指定位于任意路径下的任意名称的 Dockerfile
$ docker image build 
######### Dockerfile 指令 ###############
$ FROM    #指定构建的基础镜像
$ RUN     #在镜像层执行命令,每次使用将会构建新的镜像层
$ COPY    #将文件作为一个新的层添加到镜像中,通常使用赋值的形式
$ EXPOSE  #为镜像设置监听端口
$ ENTRYPOINT #指定镜像以容器方式默认运行的应用程序
$ LABEL   #给镜像打标签,以键值对的形式
$ ENV     #指定镜像的环境变量
$ ONBUILD  #添加镜像触发器,以当前基础镜像构建新的镜像时,会触发相应的指令
$ HEALTHCHECK #增加自定义的心跳检测功能,多次使用只有最后一次有效
$ ADD #构建镜像时,复制上下文中的文件到镜像内
$ WORKDIR #指定镜像工作目录
...

更多 Dockerfile 文件指令可到官方文档查询:https://docs.docker.com/v17.09/engine/reference/builder/

单体应用容器化

  • 获取源码

    由于我所用的学习资料是 Nigel Poulton 所著的《深入浅出 Docker》,再次感谢作者的不吝贡献!关于接下来所分析的部分,我克隆了本书作者的 Github 仓库源代码进行分析。

    $ git clone https://github.com/nigelpoulton/psweb.git #克隆源码
    $ cd psweb/
    $ ls 
    app.js  circle.yml  Dockerfile  package.json  README.md  test  views

    可以看出,整个应用容器化的结构已经一目了然了!

  • 分析 Dockerfile

    Dockerfile文件是一个包含了对当前应用的描述,并且是镜像构建必不可少的一个文件。Dockerfile 能够在开发和部署两个过程中无缝切换,因此要像源代码一样重视它,将其视为 源代码控制系统 的一部分。

    在 Docker 当中,包含 应用文件的目录通常被称为构建上下文(Bulid Context);通常将 Dockerfile 文件放到构建上下文的根目录下。

    说实话,构建上下文这个名字我始终觉得有些拗口,不过就姑且按照作者的理解来继续吧!这个概念在接下来的 Docker 学习中占据着非常重要的地位!

    关于 Dockerfile 文件的命名方式,文件的开头字母必须是大写字母D,除此以外的其他写法都是不被允许的。

    Dockerfile文件主要包括两个用途:

    • 对当前应用的描述
    • 指导 Docker 完成应用容器化

下面我们来分析 Dockerdfile 文件的每一项信息:

  1 # Test web-app to use with Pluralsight courses and Docker Deep Dive book
  2 # Linux x64
  3 FROM alpine
  4
  5 LABEL maintainer="nigelpoulton@hotmail.com"
  6
  7 # Install Node and NPM
  8 RUN apk add --update nodejs nodejs-npm
  9
 10 # Copy app to /src
 11 COPY . /src
 12
 13 WORKDIR /src
 14
 15 # Install dependencies
 16 RUN  npm install
 17
 18 EXPOSE 8080
 19
 20 ENTRYPOINT ["node", "./app.js"]
    • 每个 Dockerfile 文件的第一行是 FROM 指令,用于指定当前的基础镜像,这里选用了 alpineFROM 指令指定的镜像,会作为当前镜像的一个基础镜像层,当前应用的剩余内容会作为新增镜像层添加到基础镜像层上。此时的镜像层数为1
    • 接下来的 LABEL 标签用于指定当前镜像的维护者是 nigelpoulton@hotmail.com。每个标签是一个 键值对(key-value)的形式,在一个镜像当中可以通过增加标签的方式来为镜像增加元数据,并且备注维护者信息有助于该镜像的维护,该指令不会创建新的镜像层。
    • RUN apk add --update nodejs nodejs-npm指令使用的是 alpineapk包管理器,对 node.jsnodejs-npm安装到当前镜像中。注意,此时构建的镜像是在 FROM 指定的镜像层 alpine 之上,此时的镜像层数为2
    • COPY . /src指令表示将部署应用的相关文件 从构建上下文复制到当前镜像中/src,并新建一层镜像存储,此时的镜像层数为3
    • WORKDIR指令表示为尚未执行的指令设置 工作目录。该目录与镜像相关,并且会作为元数据记录到镜像配置中,但不会创建新的镜像层。
    • RUM npm install指令会根据 package.json 中配置信息,使用 npm 来安装当前应用相关的依赖包,并创建新的镜像层来存储相关的数据文件,此时的镜像曾数为 4.
    • EXPOSE 8080表示为应用设置网络端口号为8080,这些信息会作为元数据被保存下来,不会创建新的镜像层。
    • ENTRYPOINT ["node", "./app.js"]指令表示 指定当前镜像的入口程序 ,这些信息会作为元数据被保存下来,也不会创建新的镜像层。到这里,整个Dockerfile 文件的指令已经全部执行完毕,一共构建了 4 层镜像。
    • 容器化应用 & 构建具体的镜像

      在构建上下文目录中,执行 docker image build -t web:latest . 构建并生成一个名为 web:latest 的镜像。

      注意最后的这个点不能省略!

      $ docker image build -t web:latest . #构建镜像
      Sending build context to Docker daemon  74.75kB
      Step 1/8 : FROM alpine
       ---> 965ea09ff2eb
      Step 2/8 : LABEL maintainer="nigelpoulton@hotmail.com"
       ---> Using cache
       ---> 7c39d759f1a2
      Step 3/8 : RUN apk add --update nodejs nodejs-npm
       ---> Using cache
       ---> 9fc401a717dd
      Step 4/8 : COPY . /src
       ---> Using cache
       ---> 34d5b56b97b7
      Step 5/8 : WORKDIR /src
       ---> Using cache
       ---> 8516e5745bdf
      Step 6/8 : RUN  npm install
       ---> Using cache
       ---> eb6f3e2ecab6
      Step 7/8 : EXPOSE 8080
       ---> Using cache
       ---> 4687da82872d
      Step 8/8 : ENTRYPOINT ["node", "./app.js"]
       ---> Using cache
       ---> c862461d9b35
      Successfully built c862461d9b35 #构建镜像 ID
      Successfully tagged web:latest #构建镜像名称
      $ docker image ls #查看当前镜像 ID
      REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
      web                 latest              c862461d9b35        10 minutes ago      71.5MB
      $ docker image inspect web:latest #查看镜像的详细信息,如果有输出,证明镜像正确完成构建
    • 推送镜像到具体仓库
      前面已经提到了,Docker 公司提供了一个官方的存储仓库服务,即便 Docker Hub,在构建镜像完毕之后,可以将本地主机的镜像推送至docker hub 仓库,通过 docker login 命令执行这一操作:

      $ 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.
      Username: sunlingbot  #填入你的用户名
      Password:             #仓库密码
      WARNING! Your password will be stored unencrypted in /home/max-studio/.docker/config.json.
      Configure a credential helper to remove this warning. See
      https://docs.docker.com/engine/reference/commandline/login/#credentials-store
      Login Succeeded  #登录成功

      在推送镜像之前,还需要为镜像 打标签,这是因为 Docker 在镜像推送的时候需要以下信息:

      • Registry (镜像仓库服务)
      • Repository (镜像仓库)
      • Tag (镜像标签)

    我们无需为 RegistryTag指定值,如果没有为其指定值,Docker 会默认 Registry=docker.io(DNS 地址)Tag=latest(标签),但是 Repository 并没有默认值,而是从 REPOSITORY 属性值获取。

    $ docker image ls
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    web                 latest              c862461d9b35        10 minutes ago      71.5MB

    可以看到,镜像仓库的名称是 web,这意味着执行docker image push 命令之后,会尝试将镜像推送至 docker.io/web:latest 的仓库中,但其实 sunlingbot 这个用户并没有 web 这个镜像仓库的访问权限,所以只能尝试推送到 sunlingbot 这个二级命名空间(namespace)之下。因此需要使用 sunlingbot 这个ID,为当前镜像重新打一个标签。打标签的语法为:docker image tag <current-tag> <new-tag>

    $ docker image tag web:latest sunlingbot/web:latest #打标签
    $ docker image ls
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    web                 latest              c862461d9b35        10 minutes ago      71.5MB
    sunlingbot/web      latest              c862461d9b35        2 hours ago         71.5MB

    现在开始推送镜像docker image push <current-tag>

    $ docker image push sunlingbot/web:latest #推送镜像
    The push refers to repository [docker.io/sunlingbot/web]
    c730653e9d1d: Pushed
    9162483c7edc: Pushed
    71a8faec6d7a: Pushed
    77cae8ab23bf: Mounted from library/alpine
    latest: digest: sha256:dd7e83fcf7b416b259fbcb619d82425e23d42690af55fa981086d87dac484d33 size: 1160

    • 运行应用程序

      运行构建镜像的部署应用,只需要执行 docker container run 命令运行即可:启动一个名为 test 的容器,-p参数表示将容器 8080 端口映射到 docker 主机的 5000 端口,-d参数表示让应用程序以守护线程的方式在后台运行。执行 docker container ls 命令可以观察当前容器正在运行中!

      $ docker container run -d --name test \ #启动容器
      > -p 5000:8080 \  #端口映射 <local-port>:<container-port>
      > sunlingbot/web:latest #标签
      $ docker container ls
      CONTAINER ID    IMAGE                     COMMAND         CREATED        STATUS     
      6ae07f5218d4  sunlingbot/web:latest   "node ./app.js"   7 seconds ago  Up 7 seconds       
      PORTS                    NAMES
      0.0.0.0:5000->8080/tcp   test
    • 部署应用测试

      在浏览器输入 docker 主机的 ip:port 形式,观察到以下画面证明容器内的应用已经成功运行!

    正文完
     0