V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Goodapp
V2EX  ›  推广

Docker 第一课,吊打 Dockerfile~

  •  
  •   Goodapp · 2016-12-02 10:13:01 +08:00 · 3130 次点击
    这是一个创建于 2702 天前的主题,其中的信息可能已经有所发展或是发生改变。

    东坡并没有有诗曰:日建镜像三百个,不辞长用 Dockerfile 。 觉得镜像构建枯燥乏味?困货,快使用 Dockerfile 吧! 作为一枚构建镜像的老司机,下面跟大家聊聊 吊打 Dockerfile 的正确姿势。

    Docker 、 Dockerfile 、 Docker 镜像、容器……这都是些啥东西?

    虽是老生常谈,再再再普及一下:

    • Docker 最早是 dotcloud 公司出品的一套容器管理工具,但后来 Docker 慢慢火起来了,连公司名字都从 dotcloud 改成 Docker 。
    • Dockerfile 是 Docker 镜像的描述文件,可以理解成导弹发射的 A 、 B 、 C 、 D ……的步骤。
    • Docker 镜像是通过 Dockerfile 做出来的,包含操作系统基础文件和软件运行环境,它使用分层的存储方式。
    • 容器是运行起来的镜像, Docker 镜像相当于程序,容器相当于进程。

    讲了这么多,大家可能已经意识到了,攘外必先安内,想玩转 Docker 必须要先搞定 Docker 镜像,而镜像又来自于 Dockerfile ,因此本文从 Dockerfile 编写开始,与您分享 Docker 镜像的制作过程。

    如何通过 Dockerfile 快速构建镜像?

    接下来,我们通过构建一个 Tomcat 镜像,来演示 Dockerfile 的使用方法,当然前提是你的电脑安装了 Docker 环境, Docker 环境的安装就不在此赘述了。

    1.创建一个 Dockerfile Dockerfile 命名必须为“ Dockerfile ”, Docker 镜像构建时,会查找指定目录中的 Dockerfile 文件。

    2.编写 Dockerfile

    2.1 环境配置 首先,我们需要指定一个基础镜像,为了方便,我们从 Ubuntu 镜像开始。 FROM ubuntu:14.04

    通过 FROM 指令, Docker 编译程序能够知道通过哪个基础镜像执行来进行编译。所有的 Dockerfile 都必须以 FROM 指令开始。通过该指令,我们相当于有了一个最基本的 Ubuntu 系统。

    2.2 其他环境配置 我们可以像这样指定 Dockerfile 的作者 MAINTAINER example [email protected]

    另外我们需要指定时区,否则我们做出的镜像可能会跟当前时间不符。 RUN echo "Asia/Shanghai" > /etc/timezone;dpkg-reconfigure -f noninteractive tzdata

    我们可以像在电脑上安装 Tomcat 一样,把 Tomcat 安装在 Docker 容器中。

    2.3 Tomcat 必要软件安装。 我们此时使用的 Ubuntu 系统其实是很简陋的系统,上面很多系统都没有。所以我先安装一些必要的软件。 RUN apt-get update && apt-get install -y curl vim net-tools && \ rm -rf /var/lib/apt/lists/* && mkdir -p /app

    RUN 指令用来在 Docker 的编译环境中运行指定命令。这里我安装了 curl 、 vim 、 net-tools ,其中 curl 用来获取 java 和 tomcat 的安装包, vim 和 net-tools 用来调试,并创建了 /app 目录。

    2.4 指定工作目录 使用 WORKDIR /app 可以将工作目录定位到 /app 目录

    2.5 获取安装软件 我们使用第 3 )步安装的 curl 工具来获取安装包。 RUN curl -L 'http://download.oracle.com/otn-pub/java/jdk/7u65-b17/jdk-7u65-linux-x64.tar.gz' -H 'Cookie: oraclelicense=accept-securebackup-cookie; gpw_e24=Dockerfile' | tar -xz \ && curl -L 'http://archive.apache.org/dist/tomcat/tomcat-7/v7.0.8/bin/apache-tomcat-7.0.8.tar.gz' | tar -xz

    以上命令将会从指定地址下载安装包,并解压到当前目录(上一步我们指定了工作空间为 /app ,所以会解压到此目录下)

    2.6 指定运行脚本 截止到上一步,我们已经将需要的准备工作都做好了,剩下的还有 Java 环境变量的设置, Tomcat 环境变量设置(非必须)和 Tomcat 的启动。 COPY tomcat7.sh /app/tomcat7.sh RUN chmod +x /app/tomcat7.sh

    上面的两行命令会将与 Dockerfile 同级目录的 tomcat7.sh 文件上传到 docker 容器中的 /app 目录下,并且给该文件赋予可执行的权限。 看一眼该脚本的内容便一目了然了。

    #Java 环境变量配置 export JAVA_HOME=/app/jdk1.7.0_65 export PATH=$JAVA_HOME/bin:$PATH export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar #Tomcat 环境变量配置 export TOMCAT_HOME=/app/apache-tomcat-7.0.8 export PATH=$TOMCAT_HOME/bin:$PATH #启动 Tomcatexec $TOMCAT_HOME/bin/catalina.sh run

    2.7 指定端口 EXPOSE 8080 通常情况下, Tomcat 启动后会监听 8080 端口,在容器中也一样。 EXPOSE 指令用于标明,这个镜像中的应用将会侦听某个端口,并且希望能将这个端口映射到主机的网络界面上

    2.8 指定脚本的运行 至此,我们要做的准备工作就做完了。使用下面这条命令,运行我们在第 6 步创建的脚本,一个简单的 Tomcat 的 Dockerfile 就编写完成了。 ENTRYPOINT [“/app/tomcat7.sh"] ENTRYPOINT 用于标明一个镜像作为容器运行时,最后要执行的程序或命令。

    3.构建镜像 进入 Dockerfile 所在目录,运行命令 docker build -t mytomcat . (注意最后有个点用来表示当前目录,初次构建速度会比较慢,需要多等一会。) 出现如下信息就构建成功了 1 2

    4.运行 Docker 容器 docker run -i -t -p 5000:8080 mytom

    其中, docker run 用于运行一个容器 -t 在容器指定一个伪终端或者终端; -i 进行命令交互; -p 匹配镜像内的网络端口号,即我们可以通过宿主机中访问 5000 端口来达到访问容器 8080 端口的目的。

    5.查看构建好的镜像和运行的容器 docker images #查看镜像 3 docker ps -a #查看所有的容器 3

    6.查看服务是否运行 在宿主机中我们输入 localhost:5000 访问,出现如下界面,表示 Tomcat 成功运行。 4 至此,我们就成功的创建了一个 Tomcat 镜像了,当然这里只是为了简单演示,所以镜像做的比较简单,官方的 Tomcat 镜像比这复杂的多,在熟悉了 Dockerfile 后可以去看看官方的做法。

    7.其他 在做镜像的时候有那么多步骤,根本不可能一次将所有的步骤完成,这里给大家分享一个小技巧。 在编写完 Dockerfile 到第二步的时候,其实可以先用一个脚本运行着,然后在容器内部进行操作。笔者在编写 Dockerfile 时先使用如下命令: COPY run.sh /app/run.sh
    RUN chmod +x /app/run.sh
    ENTRYPOINT [“/app/run.sh"]

    run.sh 脚本的内容如下: #!/bin/bash
    sleep 15
    while true
    do
    echo "true"
    sleep 180
    done

    其实就是一段死循环代码代替原有的 tomcat7.sh ,接着就可以 build 和 run 我们的容器了。容器运行起来后使用 docker exec -it container_id bash 进入 docker 容器。此时就和我们平时装软件的方式一样了,做完一个步骤,在 Dockerfile 中记录一条,这样 Dockerfile 也就做出来了。(ps:exit 退出容器。)

    特别注意的一点,如果做好镜像以后,在镜像中有需要保存的数据(持久化目录)需要我们在 Dockerfile 中指定持久化目录。为了能够保存(持久化)数据以及共享容器间的数据, Docker 提出了 Volume 的概念。简单来说, Volume 就是目录或者文件,它可以绕过默认的联合文件系统,而以正常的文件或者目录的形式存在于宿主机上。并且我们运行容器的时候需要使用使用 -v 来声明 Volume ,如: docker run -it -v /home/dock/logs:/usr/logs tomcat /bin/bash

    冒号前为宿主机目录,必须为绝对路径,冒号后为镜像内挂载的路径,这样容器内更改的数据就被写到宿主机上了。 拥有了 Tomcat 服务器后,就可以跑写好的 java-web 程序了,如何运行 java-web 程序就不在此详述了,跟普通运行 java-web 程序一样。

    同样的,如果你有一个 web 应用,将其放入 Docker 容器中,写好 Dockerfile ,构建好应用运行需要的环境后,就可以很快的使用应用了。 Dockerfile 源码已放到好雨的 github 公共仓库了,上面有很多使用 Dockerfile 构建的项目。可以方便大家学习。 地址: https://github.com/goodrain-apps/tomcat-demo

    最后补充一点,好雨云帮目前支持 Java , PHP , Python 等多种语言的应用,不用自己构建具体环境,可以直接从源码进行构建,十分方便。以上说的 Dockerfile 也是支持的。如果有写好的程序想要跑起来可以参照好雨官方文档进行部署。

    作者:超儿哥,好雨科技平台研发部

    7 条回复    2016-12-05 10:58:23 +08:00
    sakeven
        1
    sakeven  
       2016-12-02 12:32:05 +08:00 via iPhone   ❤️ 1
    吊打 Dockerfile , Dockerfile 怎么敢必须命名为 Dockerfile 。
    Goodapp
        2
    Goodapp  
    OP
       2016-12-02 15:45:14 +08:00
    @sakeven 让 Dockerfile 先释放技能
    Vicer
        3
    Vicer  
       2016-12-03 10:10:39 +08:00 via Android   ❤️ 1
    我看完了
    least2011
        4
    least2011  
       2016-12-04 21:15:51 +08:00   ❤️ 1
    docker images 里出来的 image 如何删除?
    cloudbang
        5
    cloudbang  
       2016-12-05 09:36:55 +08:00
    @least2011

    使用
    ```bash
    docker rmi 容器 id
    的方式来删除。

    或者参考我写的一些容器维护脚本: https://github.com/zhouyq/stuq_dockerfile/tree/master/scripts
    P99LrYZVkZkg
        6
    P99LrYZVkZkg  
       2016-12-05 10:33:08 +08:00   ❤️ 1
    @cloudbang 学习了。
    cloudbang
        7
    cloudbang  
       2016-12-05 10:58:23 +08:00
    @P99LrYZVkZkg 做了一个 Docker 相关的问答索引,可以参考一下: http://t.goodrain.com/t/docker/234
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2809 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 15:16 · PVG 23:16 · LAX 08:16 · JFK 11:16
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.