美文网首页Kubernetes专栏
Docker:快速上路

Docker:快速上路

作者: wyatt_plus | 来源:发表于2021-03-24 09:00 被阅读0次

    一. 简介

    Docker核心是由Linux Namespace 的隔离能力、Linux Cgroups 的限制能力,以及基于 rootfs 的文件系统三个组成,

    枯燥的指令集毫无乐趣,所以我借鉴了他人的教学方法,采用一个小demo从头到尾运行一边docker镜像的全生命流程。

    二. 构建流程

    我们今天采用docker进行一个Flask Web项目的全流程构建,部署和推送等。

    相关代码在此链接中:flask_web项目地址

    2.1 构建App

    这个项目将启动一个Flask项目,暴露一个18080的端口,当访问Web根目录时,将会返回向一个'Hello World!' + hostname的字符串,hostname代表当前容器的hostname。
    app.py文件如下:

    from flask import Flask
    import socket
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello_world():
        hostname = socket.gethostname()
        return 'Hello World!' + hostname
    
    
    if __name__ == '__main__':
        app.run(host='0.0.0.0', port=18080)
    
    

    2.2 编写Dockerfile

    Dockerfile 的设计思想,是使用一些标准的原语,描述我们所要构建的 Docker 镜像。并且这些原语,都是按顺序处理的,这也算是一种应用的自描述,是一种很符合DevOps的要求。

    关于编写Dockerfile的源码也已将放到GitHub上面了,内容如下:

    
    # 拉取Python3
    FROM rackspacedot/python37
    
    # 将工作目录切换为/app
    WORKDIR /app
    
    # 将当前目录下的所有内容复制到/app下
    ADD . /app
    
    # 使用pip命令安装这个应用所需要的依赖
    RUN pip install --trusted-host pypi.python.org -r requirements.txt
    
    # 允许外界访问容器的18080端口
    EXPOSE 18080
    
    # 设置容器进程为:python app.py,即:这个Python应用的启动命令
    CMD ["python", "app.py"]
    
    

    关于docker file里面的原语内容可以如下理解:

    • FROM:指docker从rackspacedot拉取一个python37的基础镜像
    • WORKDIR:切换容器的工作目录到/app目录下
    • ADD:理解为复制dockerfile所在目录的内容到/app工作目录
    • RUN:容器里执行 shell 命令
    • EXPOSE:声明容器暴露一个端口18080
    • CMD:指定 python app.py 为这个容器的进程,app.py 的实际路径是 /app/app.py。
    • ENTRYPOINT(默认):实际进程是:/bin/sh -c "python app.py",即 CMD 的内容就是 ENTRYPOINT 的参数,所以Docker 容器的启动进程为 ENTRYPOINT,而不是 CMD。

    2.3 docker build

    docker build 会自动加载当前目录下的 Dockerfile 文件,然后按照顺序,执行文件中的原语。
    在编写Dockerfile所在的目录,执行如下的指令:

    docker build -t flask_web .
    

    关于指令细节:

    • -t:给这个镜像加一个 Tag
    • flask_web:这个镜像的名称
    build success

    Dockerfile 中的每个原语执行后,都会生成一个对应的镜像层。即使原语本身并没有明显地修改文件的操作(比如,ENV 原语),它对应的层也会存在。只不过在外界看来,这个层是空的。

    当我们构建成功后,可以使用如下指令查看本地镜像内容:

    docker image ls
    
    docker image list

    不过,上图中构建出的镜像非常大,这说明我选择的原始镜像非常有问题,这也是后续优化的点,这章不做讨论。

    2.4 docker run

    构建完的镜像都存在于本地,所以我们可以非常简单的使用docker run指令来运行。
    指令如下:

    docker run -p 18090:18080 flask_web
    

    关于指令细节,作用如下:

    • p:指定映射端口,将宿主机18090端口映射到容器的18080端口
    • flask_web:为本地flask_web的镜像名称
    runtime
    • 容器启动之后,我可以使用 docker ps命令看到:
    docker ps
    
    ps
    • 我们需要访问该web,可以浏览器访问:http://localhost:18090/
      我们将看到Hello World!2d278afce7a7的内容,代表我们容器的成功运行。

    2.5 docker push

    当我们完成镜像的编写,我们可以把这个容器的镜像上传到 DockerHub 上分享给更多的人。

    1. 首先需要注册一个 Docker Hub 账号,然后使用docker login命令登录
    2. docker tag给容器镜像取一个完整的名字
    docker tag flask_web wy1140174371/flask_web:v1.0.0
    

    具体指令作用如下:

    • flask_web:代表tag的镜像名称
    • wy1140174371:即为个人的dockerhub账户,也叫‘repository’
    • /flask_web:代表当前项目的名称
    • v1.0.0:代表tag的版本,小步增量
    1. 采用docker push推送到docker hub上
      执行如下指令:
    docker push wy1140174371/flask_web:v1.0.0
    

    上传成功后,可以在此处查看docker hub的镜像内容,flask_web

    flask_web

    2.6 docker commit(optional)

    docker commit把一个正在运行的容器,直接提交为一个镜像。一般来说,需要这么操作原因是:当这个容器运行起来后,我又在里面做了一些操作,并且要把操作结果保存到镜像里。例如我在容器内新增了一个文件。
    具体指令可以使用如下:

    docker commit container-id wy1140174371/flask_web:v1.0.1
    

    具体参数含义如下:

    • container-id:此处需要自己替换为正在运行的容器id,通过docker ps获取。
    • v1.0.1:版本注意增量

    三. Volume

    Volume 机制,允许我们将宿主机上指定的目录或者文件,挂载到容器里面进行读取和修改操作.

    3.1 俩种方式

    在 Docker 项目里,它支持两种 Volume 声明方式,可以把宿主机目录挂载进容器的 /test 目录当中:

    docker run -v /test ...
    docker run -v /home:/test ...
    

    当然俩种方式有一定的区别:

    • 不声明式
      由于没有显示声明宿主机目录,那么 Docker 就会默认在宿主机上创建一个临时目录 /var/lib/docker/volumes/[VOLUME_ID]/_data,然后把它挂载到容器的 /test 目录上。
    • 指定宿主机目录
      这种情况下,Docker 就直接把宿主机的 /home 目录挂载到容器的 /test 目录上。

    3.2 原理

    这个功能利用了Linux 的绑定挂载(bind mount)机制。它的主要作用就是,允许我们将一个目录或者文件,而不是整个设备,挂载到一个指定的目录上。并且,这时我们在该挂载点上进行的任何操作,只是发生在被挂载的目录或者文件上,而原挂载点的内容则会被隐藏起来且不受影响。

    3.3 图解

    图解如下,mount --bind /home /test,会将 /home 挂载到 /test 上。其实相当于将 /testdentry,重定向到了 /homeinode。这样当我们修改 /test 目录时,实际修改的是 /home 目录的 inode。这也就是为何,一旦执行 umount 命令,/test 目录原先的内容就会恢复:因为修改真正发生在的,是 /home 目录里。

    architecture

    四. 拓展

    4.1 docker exec

    docker exec指令可以让我们进入容器内,并在容器内执行相关操作。
    如下例子,就是一个进入容器后,并运行/bin/sh.

    docker exec -it container-id /bin/sh
    

    4.2 docker inspect

    docker inspect指令可以看到当前正在运行的 Docker 容器的进程号(PID),即宿主机上进程号。
    具体如下:

    docker inspect --format '{{ .State.Pid }}' container-id
    

    4.3 ENTRYPOINT

    Docker 容器的启动进程为 ENTRYPOINT,而不是 CMD,即 CMD 的内容就是 ENTRYPOINT 的参数。

    4.4 Docker Registry

    DockerHub只是官方的镜像上传系统,但是我们也是可以自建其他的镜像系统的,例如Harbor。就比如我们的Java领域的Maven仓库,除了maven,github,sonatype等外,也可以自建nexus仓库等,按照实际需求来即可。

    五. 总结

    关于docker已经使用很多年了,在最近的时间内重新巩固了一下基础知识。这些东西其实光看光听帮助不大,主要的是我们需要通过实操来巩固记忆。
    学习金字塔模型底层的主动式学习是最有效的方式,我一直是一个推崇方法论的实践者。
    我经过了很久的工作秘密,确定了走DevOps的方向,在此路上我还是一个新手,大家共勉。

    欢迎关注我的博客:https://blog.wyatt.plus

    Reference

    https://time.geekbang.org/column/article/18119?utm_campaign=guanwang&utm_source=baidu-ad&utm_medium=ppzq-pc&utm_content=title&utm_term=baidu-ad-ppzq-title
    http://docker-saigon.github.io/post/Docker-Internals/#how:cb6baf67dddd3a71c07abfd705dc7d4b
    https://medium.com/@kasunmaduraeng/docker-namespace-and-cgroups-dece27c209c7

    相关文章

      网友评论

        本文标题:Docker:快速上路

        本文链接:https://www.haomeiwen.com/subject/veschltx.html