• docker day04


    Dockerfile:
        - FORM:
            1.指定基础镜像,可以起别名,也可以指定多个FROM指令,用于多阶段构建;
            2.加载触发器,加载ONBUILD指令;
            3.不指定基础镜像,声明当前镜像不依赖任何镜像,官方保留字: scratch
            
        - RUN:
            1.在容器中运行命令,同一个Dockerfile中可以有多个RUN指令并不会被覆盖;
            
        - COPY:
            1.将宿主机的相对路径文件拷贝到容器中;
            2.用于多阶段构建,使用--from参数指定源阶段(编号,别名等);
            3.可以指定文件的属主和属组;
            
        - ADD:
            1.用于拷贝相对路径文件到容器中;
            2.如果源文件是tar包,会自动解压该文件;
            
        - CMD:
            1.指定容器启动的默认COMMAND;
            2.还可以和ENTRYPOINT搭配使用,作为ENTRYPOINT的参数传递;
            3.若用户启动容器时,指定的COMMAND则会覆盖CMD的指令;
            4.如果用户没有指定COMMAND且镜像也没有定义CMD则使用基础镜像的CMD指令;
            
        - ENTRYPOINT:
            1.指定容器启动的默认COMMAND
            2.还可以和CMD搭配使用,CMD将作为ENTRYPOINT的参数传递;

        - EXPOSE:
            1.暴露容器端口,多用于随机端口暴露,可以提醒用户该容器里面有哪些端口服务;
            2.端口是可以暴露多个的,比如说ftp:20,21,dns:53/udp,53/tcp,ES:9200,9300
            
        - VOLUME:
            1.对容器的路径做持久化存储,容器启动时,会创建匿名存储卷(随机存储卷);
            
        - WORKDIR:
            1.指定工作目录,当用户连接容器时默认的所在目录。
            
        - LABEL:
            打标签 
            
        - MAINTAINER:
            声明作者信息。
            
        - ENV:
            传递环境变量。
            
        - USER:
            指定服务的运行用户。
            
        - ONBUILD:
            指定基础镜像触发器。
            
        - HEALTHCHECK:
            健康检查。


    Q1: "VOLUME"能否指定一个有名称的存储卷?
        暂时不支持自定义存储卷的名称.
        
        请问若官方支持自定义名称有什么缺陷? 
            这意味基于该镜像启动的容器,都使用同一个自定义名称的存储卷。请问你这样做的目的是啥?
            
    Q2: 向容器传递参数有多少种方法,请尽可能多的说?
        1.Dockerfile ---> ENV
        2.COMMAND ---> ARGS
        3.-e,--env 
        4.ENTRYPOINT + CMD
        5.基础镜像---> 父镜像自带的变量
        
    Q3:请问容器的内核和宿主机的内核有啥关系?换句话说,将centos环境的镜像迁移到Ubuntu环境的镜像,分别启动容器,看到的内核版本是否相同?
        不同,因为容器使用和宿主机相同的内核。
        
    Q4: 虚拟机和容器有啥区别?请简要说明?
        虚拟机:
            1.虚拟的内核,效率低
            2.完全虚拟化,隔离性强
            3.占用资源多
            4.维护起来比较麻烦,启动速度慢,存在开机自启动流程;
            5.移植性差,对操作系统和软件版本依赖较高;
            6.虚拟机的镜像大,GB+
            7.不依赖于内核,可以虚拟任何操作系统;
            
        容器:
            1.使用宿主机的内容,效率高
            2.进程虚拟化,隔离性弱
            3.占用资源小
            4.维护起来简单,启动速度快,不存在开机自启动流程;
            5.移植性强,对操作系统和软件版本依赖较低;
            6.容器较小,KB+
            7.依赖LINUX内核,只能虚拟Linux发行版本的系统;
            
    Q5:为什么容器只能虚拟Linux发行版本的系统,容器能否实现资源隔离和资源限制?底层使用了什么技术?
        容器使用到了LINUX的chroot,namespace,cgroup,overlay2;


    dockerfile优化:
        编译镜像的速度:
            - ".dockerignore"文件忽略不必要文件;
            - "替换软件源仓库"从而提高下载的速度; 
            - 尽量合并指令,减少编译过程中,中间容器,镜像的产生;
            - 将不经常修改的Dockerfile指令靠前写,这样做的目的是充分利用缓存;
        
        镜像体积大小:
            - 删除缓存
            - 使用多阶段构建,只拷贝有用的软件
            - 卸载无用的软件包,比如编译安装后的编译器,下载的软件包等都可以被卸载哟;
            - 使用较小的基础镜像
                centos: 495MB
                ubuntu: 360MB
                alpine: 190MB

    2007年前后,Linux内核支持Cgroup和NameSpace技术,这两种技术在增加对Linux的整体控制的同时,也成为了保持环境隔离的重要框架。

    Linux Namespace是Linux系统提供的一种资源隔离机制,可实现系统资源隔离的列表如下:
        IPC:
            用于隔离进程间通信。
        MNT:
            用于隔离文件系统和提供硬盘挂载点。
        NET:
            用于隔离网络。
        PID:
            用于隔离进程ID。
        User:
            用于隔离用户和用户组。
        UTS:
            用于隔离HostName和DomianName。

    NET网络名称空间测试案例:
        (1)创建一个名称为"oldboyedu-linux"的网络名称空间
    ip netns add oldboyedu-linux
    ll /var/run/netns/oldboyedu-linux 
    ip netns exec oldboyedu-linux ip a

        (2)启动"oldboyedu-linux"的网络名称空间的网卡
    ip netns exec oldboyedu-linux ping 127.0.0.1  # 未启动网卡,无法ping通自己。
    ip netns exec oldboyedu-linux ifconfig lo up
    ip netns exec oldboyedu-linux ping 127.0.0.1
        
        (3)宿主机创建网络设备对
    ip link add veth100 type veth peer name veth200
    ip a   # 会多出来2块网卡,即veth100,veth200。

        (4)将"veth200"设备关联到咱们自定义的"oldboyedu-linux"网络名称空间
    ip link set veth200 netns oldboyedu-linux
    ip a  # 你会发现宿主机的veth200不见啦!

        (5)将"veth200"设备配置IP地址
    ip netns exec oldboyedu-linux ip a
    ip netns exec oldboyedu-linux ifconfig veth200 172.31.100.200/24 up
    ip netns exec oldboyedu-linux ip a

        (6)宿主机veth100也配置IP地址
    ifconfig veth100 172.31.100.100/24 up
    ifconfig veth100
    ping 172.31.100.200

        (7)oldboyedu-linux"的网络名称空间ping宿主机的IP地址
    ip netns exec oldboyedu-linux ping 172.31.100.100
    ip netns exec oldboyedu-linux ping 10.0.0.102  # 未添加网关,无法跨网段ping通
    ip netns exec oldboyedu-linux route add default gw 172.31.100.100  # 配置默认网关
    ip netns exec oldboyedu-linux ping 10.0.0.102  # Duang~可以ping通啦!
    ip netns exec oldboyedu-linux ping baidu.com  # 无法访问外网,这是正常的!此处建议pingIP地址,域名解析需要DNS。
    tcpdump -i veth100 -nn icmp  # 宿主机可以抓取到数据报文。
    ip netns exec oldboyedu-linux iptables -vnL -t nat  # 如果想要连接外网,可以尝试手动配置NAT。

        (8)测试完成后,删除名称空间
    ll /var/run/netns/   # 可以先查看挂载点文件是否存在
    ip netns del oldboyedu-linux  # 删除名称空间
    ll /var/run/netns/
    ip link del veth100    # 删除宿主机的虚拟网卡


    Linux CGroup全称Linux Control Group, 是Linux内核的一个功能,用来限制,控制与分离一个进程组群的资源(如CPU、内存、磁盘输入输出等)。

    这个项目最早是由Google的工程师在2006年发起(主要是Paul Menage和Rohit Seth),最早的名称为进程容器(process containers)。

    在2007年时,因为在Linux内核中,容器(container)这个名词太过广泛,为避免混乱,被重命名为cgroup,并且被合并到2.6.24版的内核中去。然后,其它开始了他的发展。

    如上图所示,在Linux系统中能够控制的资源列表如下:
        cpu:
            主要限制进程的cpu使用率。
        cpuacct:
            可以统计cgroups中的进程的cpu使用报告。
        cpuset:
            可以为cgroups中的进程分配单独的cpu节点或者内存节点。
        memory:
            可以限制进程的memory使用量。
        blkio:
            可以限制进程的块设备io。
        devices:
            可以控制进程能够访问某些设备。
        net_cls:
            可以标记cgroups中进程的网络数据包,然后可以使用tc模块(traffic control)对数据包进行控制。
        net_prio:
            这个子系统用来设计网络流量的优先级
        freezer:
            可以挂起或者恢复cgroups中的进程。
        ns:
            可以使不同cgroups下面的进程使用不同的namespace
        hugetlb:
            这个子系统主要针对于HugeTLB系统进行限制,这是一个大页文件系统。
            

    CPU资源限制案例:
        (1)如上图所示,可以查看Cgroup类型
    mount -t cgroup

        (2)进入到CPU的挂载路径,并创建自定义的资源限制组。
    cd /sys/fs/cgroup/cpu && mkdir oldboyedu-linux && ls oldboyedu-linux 

        (3)使用stress压力测试
    yum -y install epel-release
    yum -y install stress
    stress -c 4 -v -t 20m  # 压力测试20分钟,启动4个worker进程的CPU压测。如下图所示,4个cpu瞬间打满100%。

        (4)限制CPU的使用率在30%
    cd /sys/fs/cgroup/cpu/oldboyedu-linux && echo 30000 > cpu.cfs_quota_us

        (5)将任务的ID加入自定义限制组。
    # ps -ef | grep stress | grep -v grep
    root      9862  4432  0 11:57 pts/1    00:00:00 stress -c 4 -v -t 10m
    root      9863  9862 99 11:57 pts/1    00:06:29 stress -c 4 -v -t 10m
    root      9864  9862 99 11:57 pts/1    00:06:29 stress -c 4 -v -t 10m
    root      9865  9862 99 11:57 pts/1    00:06:29 stress -c 4 -v -t 10m
    root      9866  9862 99 11:57 pts/1    00:06:29 stress -c 4 -v -t 10m

    # cd /sys/fs/cgroup/cpu/oldboyedu-linux  # 进入到咱们自定义的限制组,分别加入限制的进程ID
    echo 9862 >> tasks    # 建议加入后,立刻查看top的信息,最好执行一个看一个效果。
    echo 9863 >> tasks   
    echo 9864 >> tasks   
    echo 9865 >> tasks   
    echo 9866 >> tasks   

    bridge:
        默认类型,桥接到宿主机docker0的网络,有点类似于VM虚拟机的NAT网络模型。
        案例:
            docker run --rm -it --network bridge --name oldboyedu-linux alpine
             
    host:
        host类型,共享宿主机的网络空间,网络性能是最高的。
        案例:
            docker run --rm -it --network host --name oldboyedu-linux alpine

    none:
        只有本地回环网卡,没有其他网络,即该容器不能上网。
        案例:
            docker run --rm -it --network none --name oldboyedu-linux alpine
            
    container:
        共享其他容器的网络,这个网络在K8S中Pod是频繁使用的。
        案例:
            docker run --rm -it --network container:web01 --name oldboyedu-linux alpine

    custom network:
        自定义网络,我们可以使用"docker network create"创建自定义网络。
        


    docker network ls
        列出当前主机的网络列表。
        
    docker network create -d bridge --subnet 192.168.100.0/24 --gateway 192.168.100.254 --ip-range 192.168.100.100/28 oldboyedu-linux
        创建自定义网络,常用的选项如下:
            -d 
                指定网络驱动,默认是bridge,也支持"ipvlan","macvlan","overlay"。
            --subnet 
                指定子网地址。
            --gateway
                指定网关地址。
            --ip-range
                指定容器的分配到子网地址。

    docker network inspect oldboyedu-linux
        查看网络的详细信息,当然也支持Go模板语法,如下所示:
            docker network inspect -f '{{range .IPAM.Config}}{{.Gateway}}{{end}}' oldboyedu-linux
            docker network inspect -f '{{range .IPAM.Config}}{{.Subnet}}{{end}}' oldboyedu-linux
            docker network inspect -f '{{range .IPAM.Config}}{{.IPRange}}{{end}}' oldboyedu-linux    
        
    docker network rm oldboyedu-linux
        删除指定的网络。
        
    docker network connect bridge web
        将brige网络连接到web容器中。
        
    docker network disconnect bridge web    
        将brige网络连接从web容器中断开。
        
    docker network prune -f
        移除所有未使用的网络。

    docker container run -id  --network oldboyedu-linux --name web alpine
        启动容器时使用咱们自定义的网络。
        
        
        
        
    (1)创建网络名称空间
    docker network create --subnet 172.20.0.0/16 --ip-range 172.20.240.0/20 zabbix-net

    (2)启动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
                 
                 
    (3)启动java gateway服务
    docker run --name zabbix-java-gateway -t \
                 --network=zabbix-net \
                 --restart unless-stopped \
                 -d zabbix/zabbix-java-gateway:alpine-5.4-latest
                 
                 
    (4)启动zabbix server服务
    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
          
          
    (5)启动zabbix web服务
    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默认的用户名为'Admin',密码为'zabbix'。    
        
        
    参考链接:
        https://www.zabbix.com/documentation/5.4/en/manual/installation/containers
        
        
        
        
        

    # 1.创建网络
    docker network create --subnet 172.20.0.0/16 --ip-range 172.20.240.0/20 zabbix-net

    # 2.启动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
          
    # 3.启动Java-gateway
    docker run --name zabbix-java-gateway -t \
          --network=zabbix-net \
          --restart unless-stopped \
          -d zabbix/zabbix-java-gateway:alpine-6.2-latest
          
    # 4.启动zabbix-server
    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-6.2-latest
          
    # 5.启动zabbix-web
    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-6.2-latest

  • 相关阅读:
    Kafka 社区KIP-405中文译文(分层存储)
    Nginx负载均衡详解
    Android NDK make.exe: *** No rule to make target
    【初识Linux】:常见指令(1)
    Linux PAGE_ALIGN 宏定义的理解
    8.3 矢量图层点要素单一符号使用二
    ES6面向对象思想和构造对象方式
    聊一聊 TLS/SSL
    javaee 事务的传播行为
    Python 项目一 数据可视化 02
  • 原文地址:https://blog.csdn.net/lpx1249115962/article/details/132927601