• 通过 DockerFile 打包镜像


    在介绍 Docker 具体的操作前,先简要复习下 Docker 的架构,这样可以更好地帮助我们理解 Docker 中的各个命令。

    首先我们一直对 Docker 这个叫法就有些误解,Docker 其实指代的是用于开发,部署,运行应用的一个平台。平常中说的 Docker 准确来说是 Docker Engine.

    Docker Engine 是一个 C/S 架构的应用。其中主要的组件有:

    • Docker Server:长时间运行在后台的程序,就是熟悉的 daemon 进程.
    • Docker Client: 命令行接口的客户端。
    • REST API: 用于和 daemon 进程的交互。

    我们通过给 Docker Client 下发各种指令,然后 Client 通过 Docker daemon 提供的 REST API 接口进行交互,来让 daemon 处理编译,运行,部署容器的繁重工作。 大多数情况下, Docker Client 和 Docker Daemon 运行在同一个系统下,但有时也可以使用 Docker Client 来连接远程的 Docker Daemon 进程,也就是远程的 Server 端。

    清楚了 Docker 的简单架构,就可以了解下具体的命令了。

    Docker 镜像构建指令

    指令1:构建镜像

    docker build [OPTIONS] PATH | URL | -
    

    Docker 构建镜像的上下文。

    这里的上下文指的就是命令的最后一个参数 PATH | URL| -,具体来说就 docker build . 中的 . 很多人以为这个 . 是 DockerFile 的位置,其实不然,准确来说是构建上下文的位置。前面说到 Docker 是 C/S 架构,在 Client 端下发具体的命令,在 Server 端(Daemon)执行具体的内容。这也就意味着,构建镜像的过程其实是在 Server 端完成的。而上下文的出现,就是为了把需要的内容传递给 Server,这也就为什么在每次构建时都能看到这样一句话。

    [root@localhost python_shell]# docker build --rm -t temp/python-test .
    Sending build context to Docker daemon  4.608kB
    

    这里的 Sending 其实就是把本地 Client 端的文件内容,拷贝到 Server 端。而许多初学者,在 DockerFile 中写出了 COPY /opt/xxxx /app 这样的话,其实就是没有理解上下文的概念,并不知道在 Server 端是没有 opt/xxxx 的文件的。

    还有的人将 Docker File 放在硬盘根目录执行,殊不知,这样会将根目录所有的文件都拷贝到 Server 端,造成构建极其缓慢。

    Options 常用参数:

    • -t: 打包出镜像的名称及标签,通常写法为 name:tag
    • --rm: 构建成功后,删除中间产生的容器。
    • --force-rm=true: 无论是否构建成功,都删除中间产生的容器
    • --no-cache: 构建镜像时不使用缓存。
    • -f: 指定 DockerFile 的路径
    docker build --no-cache --force-rm -t --no-cache local/centos7:v1 . 
    

    DockerFile 指令及编写规范

    指令1:指定基础镜像

    通过 FROM 来制定基础镜像,命令很简单,但有一点需要注意的是,一定确切指定基础镜像的版本,而不是写成 latesst, 因为随着时间推移,官方的最新镜像都会一直更新,这样就会造成无法构建的情况。

    FROM centos:7 # That's perfect!
    FROM centos:latest # That's so bad!
    

    指令2:容器中执行命令

    RUN 命令用于在容器中执行命令行的命令。一般有两种写法:

    • shell 形式:

    RUN 后面直接跟 shell 命令就可以了。切记,在 shell 形式下,不要把命令拆成多行 RUN。因为每一次的 RUN 都会构建一层新的镜像,保存了很多没有用的运行信息。而且 Union FS 是由最大层数限制的。所以尽量将命令合成一行。

    RUN yum -y install httpd; yum clean all; systemctl enable httpd.service # That's perfect!
    
    RUM yum -y install httpd / # Another perfect solution!
        yum clean all /
        systemctl enable httpd.service 
    
    RUN yum -y install httpd # That's so bad!
    RUN yum clean all;
    ....
    

    还有一点需要注意,把构建时没用的依赖包想着清空。否则的话,随着镜像的重复构建,保存了大量的没有信息。

    • exec 写法

    exec 写法更像函数调用中的格式。

    RUN ["可执行文件", "参数1", "参数2"]
    
    RUN ["yum", "-y", "install", "httpd"]
    

    指令3:设置工作目录

    WORKDIR 用于改变各层的工作目录(也就是进入容器内的默认目录),如果指定的目录不存在就会创建它。工作目录在构建过程中,可以被各层都访问到。

    WORKDIR /src
    

    指令4:设置匿名卷

    在容器运行时,尽量对容器的存储层不进行写操作,对于像数据库中这样动态的数据文件应该用 VOLUME 来保存。而在 DockerFile VOLUME 可以将目录指定为匿名卷。这样在运行时,如果没有挂载指定的目录,并不会像容器的存储层写入数据,保证存储层的无状态化。

    VOLUME /data
    

    开启 Systemd Centos7 镜像

    官方 Centos7 的镜像已经包含了 systemd 的功能,只是没有开启。这里只需要以其为基础镜像,打开 systemd 的功能即可。需要注意的是,打开 systemd 需要在运行时开启特权以挂载 Cgroup 等内容。

    编写 DockerFile

    [root@localhost docker_images]# cat Dockerfile
    FROM centos:7
    
    ENV container docker
    
    RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == 
    systemd-tmpfiles-setup.service ] || rm -f $i; done); 
    rm -f /lib/systemd/system/multi-user.target.wants/*;
    rm -f /etc/systemd/system/*.wants/*;
    rm -f /lib/systemd/system/local-fs.target.wants/*; 
    rm -f /lib/systemd/system/sockets.target.wants/*udev*; 
    rm -f /lib/systemd/system/sockets.target.wants/*initctl*; 
    rm -f /lib/systemd/system/basic.target.wants/*;
    rm -f /lib/systemd/system/anaconda.target.wants/*;
    
    VOLUME [ "/sys/fs/cgroup" ]
    
    CMD ["/usr/sbin/init"]
    
    • VOLUME 指定了匿名目录,不会在存储层保存该目录的内容,适用于动态变化等持久性文件。
    • CMD 保证容器启动时开启 systemd

    打包镜像

     docker build --rm -t local/c7-systemd .
    
    • --rm: 表示删除打包时临时的容器

    运行镜像

    docker run --privileged=true -ti -v /sys/fs/cgroup:/sys/fs/cgroup:ro local/c7-systemd
    
    • --privileged: 给予容器特殊的权限,来挂载 Cgroup 等。

    Httpd 镜像

    下面基于上面开启 systemd 的镜像为基础,打包 Httpd 镜像。

    编写 DockerFile

    FROM local/c7-systemd
    
    RUN yum -y install httpd; yum clean all; systemctl enable httpd.service
    
    EXPOSE 80
    
    • 下载依赖包后,删除没有用的内容,是编写 DockerFile 好习惯。

    编译 DockerFile

    docker build --rm -t local/c7-systemd-httpd .
    

    运行 Container

    docker run --privileged=true -ti -v /sys/fs/cgroup:/sys/fs/cgroup:ro 
    -p 80:80 local/c7-systemd-httpd
    

    在下载依赖时出现网络问题,请查看 Docker 代理 这篇文章。

    Python 镜像

    有时我们需要在容器中运行 python 脚本,下面来打包类似的镜像。在下载需要的依赖时,通常的服务器并没访问公网的能力,这时需要为容器配置配置代理,在下载依赖后,有时由于代理的原因,导致内部的服务器无法访问,这时可以再将设置的代理清空。

    创建文件

    注意,这里的文件要和 DockerFile 在同级目录下。

    # 创建 requirements 文件保存依赖
    [root@localhost home]# cat python_shell/requirements.txt
    requests==2.21.0
    
    # 编写 Python 脚本
    [root@localhost home]# cat python_shell/success.py
    print("python Running", "!");
    

    编写 DockerFile

    FROM python:3.6.8
    
    # set proxy
    ENV MY_PROXY_URL="http://173.39.112.117:80"
    ENV HTTP_PROXY=$MY_PROXY_URL 
        HTTPS_PROXY=$MY_PROXY_URL 
        FTP_PROXY=$MY_PROXY_URL 
        http_proxy=$MY_PROXY_URL 
        https_proxy=$MY_PROXY_URL 
        ftp_proxy=$MY_PROXY_URL
    
    WORKDIR /src
    
    COPY . .
    
    RUN ["pip", "install", "--no-cache-dir",  "-r",  "./requirements.txt"]
    
    # clear the proxy
    ENV MY_PROXY_URL=
    ENV HTTP_PROXY=$MY_PROXY_URL 
        HTTPS_PROXY=$MY_PROXY_URL 
        FTP_PROXY=$MY_PROXY_URL 
        http_proxy=$MY_PROXY_URL 
        https_proxy=$MY_PROXY_URL 
        ftp_proxy=$MY_PROXY_URL
    
    
    CMD ["python", "./success.py"]
    

    打包镜像

    docker build --rm -t temp/python-test .
    

    运行镜像

    [root@localhost home]# docker run temp/python-test
    python Running !
    

    参考

    docker-overview

    docker-centos-image

    docker-python-image

    https://blog.fundebug.com/2017/05/15/write-excellent-dockerfile/

    dockerfile_best-practices

    docker-chinese-reference

  • 相关阅读:
    Wamp 访问本地站点慢 的解决办法
    PHP中如何实现 “在页面中一边执行一边输出” 的效果
    PHP很有用的一个函数ignore_user_abort ()
    PHP中CURL方法curl_setopt()函数的一些参数
    RGB转为Lab空间
    void v.s. void *
    __attribute__((regparm(3))) from GNU C
    a number of 和the number of用法
    Linux 版本查詢
    在frameset,iframe內調用Javascript的方法
  • 原文地址:https://www.cnblogs.com/michael9/p/12303748.html
Copyright © 2020-2023  润新知