• Docker从入门到精通<2>-Docker的架构、内部组件、底层原理


    Docker架构

    docker是一个典型的CS架构,docker client通过REST API、UNIX套接字或者网络接口和docker daemon进行通信,后者来执行构建、运行、分发工作。

    docker client和 docker daemonset可以在同一台机器或者不同的机器上面。

    下面介绍几点基本概念:

    • Docker client:docker客户端
    • Docker daemon:docker服务端
    • Registry:保存docker镜像的仓库,Docker hub是一个任何人都可以使用的公共镜像仓库。在国外,访问速度比较慢。一般生产环境中都建设自己的镜像仓库。
    • images:一个image是创建一个容器的只读模板。通常一个镜像是基于另外一个镜像,并额外加上一些自定义的内容
    • contaners:容器,即一个image运行状态下就是一个容器 

     最核心的三个部分:容器、镜像、仓库

    Docker 内部组件

    从 Docker 1.11 之后,Docker Daemon 被分成了多个模块以适应 OCI 标准。拆分之后,结构分成了以下几个部分

    • docker: docker的客户端
    • dockerd:  docker的服务端
    • containerd:高性能的容器运行时(containerd 独立负责容器运行时和生命周期(如创建、启动、停止、中止、信号处理、删除等),其他一些如镜像构建、卷管理、日志等由 Docker Daemon 的其他模块处理,包含containerd-shim)
    • containerd-shim:是一个真实运行的容器的真实垫片载体,每启动一个容器都会起一个新的containerd-shim的一个进程,调用runc的api操作容器
    • docker-proxy:容器代理。提供docker容器的端口映射功能

     关于kubernetes弃用docker一事儿(k8s 1.20正式弃用docker-shim),估计大家都被标题党给忽悠了。kubernetes当初选择docker作为其容器运行时,是因为当时docker大火,而没有几个人知道kubernetes,为了更好支持k8s运行docker容器而开发维护一个兼容的程序叫docker-shim。真正弃用的不用docker,而是docker-shim插件的维护支持。

    至于为什么要弃用docker-shim呢?

    之前:

    之后:

    还要从k8s 在2016年发布CRI(Container Runtime Interface)标准来说起,为了支持 CoreOS 领导的容器运行时项目 rkt ,写了很多的代码。由于担心以后可能会有更新容器项目需要兼容而带来更大维护工作,所以发布了这个标准。这样的话,以后不管哪个容器项目只要支持CRL标准,就可以直接作为k8s的底层运行时。

    2017 年, Docker v1.11 开始引入的容器运行时 containerd,并捐献给了CNCF,同年11月,kubernetes开始支持containerd,containerd相对于docker而言更加轻量级,是一个行业标准的运行时,强调简单性、健壮性和可移植性。

    Docker的底层技术

    主要是基于内核提供的namespace和cgroups技术。

    namespace

     namespace提供了一下6种资源隔离机制:

    • Mount: 隔离文件系统挂载点
    • UTS: 隔离主机名和域名信息
    • IPC: 隔离进程间通信
    • PID: 隔离进程的ID
    • Network: 隔离网络资源
    • User: 隔离用户和用户组的ID

    查看当前shell 进程所在的namespace

    [root@vm1 ~]# ll /proc/$$/ns
    总用量 0
    lrwxrwxrwx 1 root root 0 7月   6 11:44 ipc -> ipc:[4026531839]
    lrwxrwxrwx 1 root root 0 7月   6 11:44 mnt -> mnt:[4026531840]
    lrwxrwxrwx 1 root root 0 7月   6 11:44 net -> net:[4026531956]
    lrwxrwxrwx 1 root root 0 7月   6 11:44 pid -> pid:[4026531836]
    lrwxrwxrwx 1 root root 0 7月   6 11:44 user -> user:[4026531837]
    lrwxrwxrwx 1 root root 0 7月   6 11:44 uts -> uts:[4026531838]
    

    cgroups  

    cgroups可以限制、记录任务组所使用的物理资源(包括CPU、Memory、IO等),为容器实现虚拟化提供了基本保证,是构建Docker等一系列虚拟化管理工具的基石。

     实现cgroups的主要目的是为不同用户层面的资源管理,提供一个统一化的接口。从单个任务的资源控制到操作系统层面的虚拟化,

    cgroups提供了以下四大功能[插图]。

    ❏ 资源限制:cgroups可以对任务使用的资源总额进行限制。如设定应用运行时使用内存的上限,一旦超过这个配额就发出OOM(Out of Memory)提示。

    ❏ 优先级分配:通过分配的CPU时间片数量及磁盘IO带宽大小,实际上就相当于控制了任务运行的优先级。

    ❏ 资源统计:cgroups可以统计系统的资源使用量,如CPU使用时长、内存用量等,这个功能非常适用于计费。

    ❏ 任务控制:cgroups可以对任务执行挂起、恢复等操作

    首先,当我们登录到操作系统之后,可以通过 ps 等操作看到各式各样的进程,这些进程包括系统自带的服务和用户的应用进程。那么,这些进程都有什么样的特点?

    • 第一,这些进程可以相互看到、相互通信;
    • 第二,它们使用的是同一个文件系统,可以对同一个文件进行读写操作;
    • 第三,这些进程会使用相同的系统资源。

    这样的三个特点会带来什么问题呢?

    • 因为这些进程能够相互看到并且进行通信,高级权限的进程可以攻击其他进程;
    • 因为它们使用的是同一个文件系统,因此会带来两个问题:这些进程可以对于已有的数据进行增删改查,具有高级权限的进程可能会将其他进程的数据删除掉,破坏掉其他进程的正常运行;此外,进程与进程之间的依赖可能会存在冲突,如此一来就会给运维带来很大的压力;
    • 因为这些进程使用的是同一个宿主机的资源,应用之间可能会存在资源抢占的问题,当一个应用需要消耗大量 CPU 和内存资源的时候,就可能会破坏其他应用的运行,导致其他应用无法正常地提供服务。

    针对上述的三个问题,如何为进程提供一个独立的运行环境呢?

    • 针对不同进程使用同一个文件系统所造成的问题而言,Linux 和 Unix 操作系统可以通过 chroot 系统调用将子目录变成根目录,达到视图级别的隔离;进程在 chroot 的帮助下可以具有独立的文件系统,对于这样的文件系统进行增删改查不会影响到其他进程;
    • 因为进程之间相互可见并且可以相互通信,使用 Namespace 技术来实现进程在资源的视图上进行隔离。在 chroot 和 Namespace 的帮助下,进程就能够运行在一个独立的环境下了;
    • 但在独立的环境下,进程所使用的还是同一个操作系统的资源,一些进程可能会侵蚀掉整个系统的资源。为了减少进程彼此之间的影响,可以通过 Cgroup 来限制其资源使用率,设置其能够使用的 CPU 以及内存量。

    那么,应该如何定义这样的进程集合呢?

    其实,容器就是一个视图隔离、资源可限制、独立文件系统的进程集合。所谓“视图隔离”就是能够看到部分进程以及具有独立的主机名等;控制资源使用率则是可以对于内存大小以及 CPU 使用个数等进行限制。容器就是一个进程集合,它将系统的其他资源隔离开来,具有自己独立的资源视图。

    容器具有一个独立的文件系统,因为使用的是系统的资源,所以在独立的文件系统内不需要具备内核相关的代码或者工具,我们只需要提供容器所需的二进制文件、配置文件以及依赖即可。只要容器运行时所需的文件集合都能够具备,那么这个容器就能够运行起来。

    docker启动快速构建zabbix server

    镜像加速

    为了加快docker拉取镜像的速度,这里我们配置了docker镜像加速:
    vi /etc/docker/daemon.json
    {
      "registry-mirrors": ["https://registry.docker-cn.com"]
    }
    systemctl  restart docker
    

      

    # 规划好zabbix server容器所需要的网段
    docker network create --subnet 172.20.0.0/16 --ip-range 172.20.240.0/20 zabbix-net
    
    # 起一个mysql的容器实例
    docker run --name mysql-server -t 
          -e MYSQL_DATABASE="zabbix" 
          -e MYSQL_USER="zabbix" 
          -e MYSQL_PASSWORD="zabbix_pwd" 
          -e MYSQL_ROOT_PASSWORD="root_pwd" 
          --network=zabbix-net 
          --restart unless-stopped 
          -d mysql:8.0 
          --character-set-server=utf8 --collation-server=utf8_bin 
          --default-authentication-plugin=mysql_native_password
    
    # 启动zabbix gateway
    docker run --name zabbix-java-gateway -t 
          --network=zabbix-net 
          --restart unless-stopped 
          -d zabbix/zabbix-java-gateway:alpine-5.4-latest
    
    # 启动zabbix server连接mysql
    docker run --name zabbix-server-mysql -t 
          -e DB_SERVER_HOST="mysql-server" 
          -e MYSQL_DATABASE="zabbix" 
          -e MYSQL_USER="zabbix" 
          -e MYSQL_PASSWORD="zabbix_pwd" 
          -e MYSQL_ROOT_PASSWORD="root_pwd" 
          -e ZBX_JAVAGATEWAY="zabbix-java-gateway" 
          --network=zabbix-net 
          -p 10051:10051 
          --restart unless-stopped 
          -d zabbix/zabbix-server-mysql:alpine-5.4-latest
    
    # 启动zabbix web连接zabbix server和mysql
    docker run --name zabbix-web-nginx-mysql -t 
          -e ZBX_SERVER_HOST="zabbix-server-mysql" 
          -e DB_SERVER_HOST="mysql-server" 
          -e MYSQL_DATABASE="zabbix" 
          -e MYSQL_USER="zabbix" 
          -e MYSQL_PASSWORD="zabbix_pwd" 
          -e MYSQL_ROOT_PASSWORD="root_pwd" 
          --network=zabbix-net 
          -p 80:8080 
          --restart unless-stopped 
          -d zabbix/zabbix-web-nginx-mysql:alpine-5.4-latest
    

      

    细心的同学会发现,彼此独立的两个容器,他们之间是如何直接通信的呢?zabbix-server-mysql是如何连接上数据库的呢?在以前的docker版本中需要强制加上--link的功能,新版本废弃了这一做法。采用的默认桥接的自定义网络内,共享环境变量。这里容器之间直接通过环境变量可以互相通信了。比如zabbix-server-mysql 通过直接连接环境变量mysql-server就可以直接找到mysql-server的容器了。

    下面我们看下容器运行状态

    [root@vm1 ~]# docker ps
    CONTAINER ID   IMAGE                                             COMMAND                  CREATED         STATUS         PORTS                                             NAMES
    ca8d68c8cfa6   zabbix/zabbix-web-nginx-mysql:alpine-5.4-latest   "docker-entrypoint.sh"   3 minutes ago   Up 3 minutes   8443/tcp, 0.0.0.0:80->8080/tcp, :::80->8080/tcp   zabbix-web-nginx-mysql
    531a2094920f   zabbix/zabbix-server-mysql:alpine-5.4-latest      "/sbin/tini -- /usr/…"   3 minutes ago   Up 3 minutes   0.0.0.0:10051->10051/tcp, :::10051->10051/tcp     zabbix-server-mysql
    6e84835cfc35   zabbix/zabbix-java-gateway:alpine-5.4-latest      "docker-entrypoint.s…"   3 minutes ago   Up 3 minutes   10052/tcp                                         zabbix-java-gateway
    5a10d9352e1e   mysql:8.0                                         "docker-entrypoint.s…"   3 minutes ago   Up 3 minutes   3306/tcp, 33060/tcp                               mysql-server
    [root@vm1 ~]#
    [root@vm1 ~]# pstree
    systemd─┬─NetworkManager───2*[{NetworkManager}]
            ├─auditd───{auditd}
            ├─containerd───9*[{containerd}]
            ├─containerd-shim─┬─mysqld───38*[{mysqld}]
            │                 └─14*[{containerd-shim}]
            ├─containerd-shim─┬─java───17*[{java}]
            │                 └─14*[{containerd-shim}]
            ├─containerd-shim─┬─tini───docker-entrypoi─┬─mysql
            │                 │                        └─zcat───zcat
            │                 └─14*[{containerd-shim}]
            ├─containerd-shim─┬─supervisord─┬─nginx───5*[nginx]
            │                 │             └─php-fpm7───5*[php-fpm7]
            │                 └─13*[{containerd-shim}]
            ├─crond
            ├─dbus-daemon───{dbus-daemon}
            ├─dockerd─┬─4*[docker-proxy───4*[{docker-proxy}]]
            │         └─13*[{dockerd}]
            ├─login───bash
            ├─lvmetad
            ├─master─┬─pickup
            │        └─qmgr
            ├─polkitd───6*[{polkitd}]
            ├─rsyslogd───2*[{rsyslogd}]
            ├─sshd───sshd───bash───pstree
            ├─systemd-journal
            ├─systemd-logind
            ├─systemd-udevd
            └─tuned───4*[{tuned}]
    

      总共启动了四个容器,docker分别启动四个containerd-shim的进程来运行四个容器。此时containerd也是独立服务,独立于docker daemon之外。

      

    需要耐心等待一会儿,此时数据库需要初始化,zabbix库也需要初始化,如果有报错,主要看日志排错。

     输入默认的用户名:Admin  密码:zabbix

    拥抱不确定,未来可期!喜欢该文章请不吝点赞推荐,如有疑问欢迎留言,我们一起探讨。
  • 相关阅读:
    软件工程--团队作业3
    软件工程--团队作业2
    软件工程第二次作业---结对编程
    软件工程第一次作业补充
    软件工程第一次作业
    用Use Case获取需求的方法是否有什么缺陷,还有什么地方需要改进?
    买卖股票的最佳时机
    爬楼梯
    删除排序数组中的重复数字
    1500802035王叔文
  • 原文地址:https://www.cnblogs.com/yang-ning/p/14976022.html
Copyright © 2020-2023  润新知