2. Docker安装和操作

1 Docker安装

1.1 Docker安装准备

  • OS版本要求: Linux内核3.10版本或以上
  • 建议使用Ubuntu, 内核版本更新
  • 1.2 安装和删除方法

    1.2.1 Ubuntu安装Docker

  • 阿里云安装教程: https://developer.aliyun.com/mirror/docker-ce?spm=a2c6h.13651102.0.0.3e221b11jtsWrr
  • Ubuntu-1804一键安装脚本
  • #!/bin/bash 
    COLOR="echo -e \033[1;31m"
    END="\033[0m"
    DOCKER_VERSION="5:19.03.12~3-0~ubuntu-bionic"  # 如需安装其他版本的docker, 要注意和Ubuntu的版本匹配
    install_docker(){
        dpkg -s docker-ce &> /dev/null && ${COLOR}"Docker已安装, 退出"${END} && exit
        apt update
        apt -y install apt-transport-https ca-certificates curl software-properties-common
        curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
        add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
        apt update
        ${COLOR}"5秒后即将安装: docker-"${DOCKER_VERSION}"版本......"${END}
        ${COLOR}"如果想安装其他版本Docker, 请按ctrl+c键退出, 修改版本再执行"${END}
        sleep 5
        apt -y install docker-ce=${DOCKER_VERSION} docker-ce-cli=${DOCKER_VERSION}
        mkdir -p /etc/docker
        tee /etc/docker/daemon.json <<-EOF
      "registry-mirrors": ["https://xxxxxxx(改成自己的阿里云加速器).mirror.aliyuncs.com"]
        systemctl daemon-reload
        systemctl enable --now docker
        docker version && ${COLOR}"Docker 安装成功"${END} || ${COLOR}"Docker 安装失败"${END}
    install_docker
    

    1.2.2 取消阿里云加速

    root@ubuntu1804-1:~# rm -rf  /etc/docker/daemon.json
    root@ubuntu1804-1:~# systemctl daemon-reload
    root@ubuntu1804-1:~# systemctl restart docker
    

    1.2.3 Docker删除

    apt purge docker-ce -y
    rm -rf /var/lib/docker
    rm -rf /var/lib/containerd
    

    1.3 Docker基础信息查看

  • docker运行的是dockerd进程, 默认不会监听端口
  • root@ubuntu1804-1:~# ss -ntl
    State              Recv-Q              Send-Q                            Local Address:Port                           Peer Address:Port             
    LISTEN             0                   128                               127.0.0.53%lo:53                                  0.0.0.0:*                
    LISTEN             0                   128                                     0.0.0.0:22                                  0.0.0.0:*                
    LISTEN             0                   128                                        [::]:22                                     [::]:*                
    root@ubuntu1804-1:~# systemctl restart docker
    root@ubuntu1804-1:~# ss -ntl
    State              Recv-Q              Send-Q                            Local Address:Port                           Peer Address:Port             
    LISTEN             0                   128                               127.0.0.53%lo:53                                  0.0.0.0:*                
    LISTEN             0                   128                                     0.0.0.0:22                                  0.0.0.0:*                
    LISTEN             0                   128                                        [::]:22                                     [::]:*                
    root@ubuntu1804-1:~# ss -ntlp
    State       Recv-Q       Send-Q              Local Address:Port             Peer Address:Port                                                       
    LISTEN      0            128                 127.0.0.53%lo:53                    0.0.0.0:*          users:(("systemd-resolve",pid=741,fd=13))       
    LISTEN      0            128                       0.0.0.0:22                    0.0.0.0:*          users:(("sshd",pid=902,fd=3))                   
    LISTEN      0            128                          [::]:22                       [::]:*          users:(("sshd",pid=902,fd=4)) 
    
  • dockerd是docker的后台守护进程, 但是运行容器时, 是运行在containerd上的, 因为docker使用containerd做为high-level的runtime
  • root      19635  0.1  9.0 764048 88940 ?        Ssl  20:58   0:00 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
    root      21325  0.0  0.1  14428  1104 pts/0    S+   21:01   0:00 grep --color=auto docker
    root        781  0.1  4.7 772596 46408 ?        Ssl  00:14   0:00 /usr/bin/containerd
    root       1757  0.0  0.5 108596  5320 ?        Sl   00:20   0:00  \_ containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.run
    root       1781  3.0  0.5  10632  5832 ?        Ss   00:20   0:00      \_ nginx: master process nginx -g daemon off;
    systemd+   1842  0.0  0.2  11060  2640 ?        S    00:20   0:00          \_ nginx: worker process
    
  • docker version, 查看Docker版本
  • root@ubuntu1804-1:~# docker version
    Client: Docker Engine - Community
     Version:           19.03.12
     API version:       1.40
     Go version:        go1.13.10
     Git commit:        48a66213fe
     Built:             Mon Jun 22 15:45:36 2020
     OS/Arch:           linux/amd64
     Experimental:      false
    Server: Docker Engine - Community
     Engine:
      Version:          19.03.12
      API version:      1.40 (minimum version 1.12)
      Go version:       go1.13.10
      Git commit:       48a66213fe
      Built:            Mon Jun 22 15:44:07 2020
      OS/Arch:          linux/amd64
      Experimental:     false
     containerd:
      Version:          1.2.13
      GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
     runc:
      Version:          1.0.0-rc10
      GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
     docker-init:
      Version:          0.18.0
      GitCommit:        fec3683
    
  • docker info, 查看Docker信息
  • root@ubuntu1804-1:~# docker info
    Client:
     Debug Mode: false
    Server:
     Containers: 1
      Running: 0
      Paused: 0
      Stopped: 1
     Images: 4
     Server Version: 19.03.12
     Storage Driver: overlay2
      Backing Filesystem: extfs
      Supports d_type: true
      Native Overlay Diff: true
     Logging Driver: json-file
     Cgroup Driver: cgroupfs
     Plugins:
      Volume: local
      Network: bridge host ipvlan macvlan null overlay
      Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
     Swarm: inactive
     Runtimes: runc  # low level运行时
     Default Runtime: runc
     Init Binary: docker-init
     containerd version: 7ad184331fa3e55e52b890ea95e65ba581ae3429
     runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd
     init version: fec3683
     Security Options:
      apparmor
      seccomp
       Profile: default
     Kernel Version: 4.15.0-76-generic
     Operating System: Ubuntu 18.04.4 LTS
     OSType: linux
     Architecture: x86_64
     CPUs: 1
     Total Memory: 1.924GiB
     Name: ubuntu1804-1
     ID: IEZZ:XGGE:CLQL:WJ4Q:V7BT:ABW3:J7CO:KQY7:QV2U:GIIW:VWXF:DK7O
     Docker Root Dir: /var/lib/docker
     Debug Mode: false
     Registry: https://index.docker.io/v1/
     Labels:
     Experimental: false
     Insecure Registries:
      127.0.0.0/8
     Live Restore Enabled: false
    WARNING: No swap limit support
    
  • docker service
  • root@ubuntu1804-1:~# systemctl status docker
     docker.service - Docker Application Container Engine
       Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
       Active: active (running) since Mon 2020-08-03 13:32:06 AEST; 8h ago
         Docs: https://docs.docker.com
     Main PID: 847 (dockerd)
        Tasks: 8
       CGroup: /system.slice/docker.service
               └─847 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
    
  • docker-客户端工具
  • which docker
    /usr/bin/docker
    
  • docker的socket文件
  • docker默认工作在本地, 可以使其监听在tcp|udp协议某个端口上来实现网络功能
  • docker主程序dockerd(默认监听本地的socket文件/var/run/docker.sock=)
  • docker客户端和本地的dockerd服务端通信,靠的是/var/run/docker.sock=文件实现的
  • root@ubuntu1804-1:~# ps aux | grep dockerd
    root        847  0.0  3.9 754420 80384 ?        Ssl  13:31   0:07 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
    root       3825  0.0  0.0  14428  1088 pts/1    S+   22:33   0:00 grep --color=auto dockerd
    root@ubuntu1804-1:~# ll /var/run/docker.sock
    srw-rw---- 1 root docker 0 Aug  3 13:31 /var/run/docker.sock=   # "="表明此文件的文件类型是socket文件. Ubuntu"ll"命令是`ls -alF`的别名, 会显示文件类型
    root@ubuntu1804-1:~# alias ll
    alias ll='ls -alF'
    
  • 如果把docker服务停止, 会发现docker.socket=仍然存在
  • root@ubuntu1804-1:~# systemctl stop docker
    root@ubuntu1804-1:~# systemctl stop docker.socket
    root@ubuntu1804-1:~# ll /var/run/docker.sock
    srw-rw---- 1 root docker 0 Aug  3 13:31 /var/run/docker.sock=
    
  • 哪怕把这个文件删了,重启服务后该文件也会自动生成, 有了socket文件,客户端和服务端就可以通信了
  • root@ubuntu1804-1:~# ll /var/run/docker.sock
    srw-rw---- 1 root docker 0 Aug  3 13:31 /var/run/docker.sock=
    root@ubuntu1804-1:~# rm -rf /var/run/docker.sock
    # 删除后, docker客户端就无法连接到docker服务器引擎了. 执行docker version只会返回docker客户端信息
    root@ubuntu1804-1:~# docker version
    Client: Docker Engine - Community
     Version:           19.03.12
     API version:       1.40
     Go version:        go1.13.10
     Git commit:        48a66213fe
     Built:             Mon Jun 22 17:45:36 2020
     OS/Arch:           linux/amd64
     Experimental:      false
    root@ubuntu1804-1:~# systemctl restart docker
    root@ubuntu1804-1:~# ll /var/run/docker.sock
    srw-rw---- 1 root docker 0 Aug  3 22:42 /var/run/docker.sock=
    
  • dockerd -H [选项], 实现docker网络通信, 可以跨网络管理
  • 1 修改服务器端标签: 修改服务器端service文件标签用来区分客户端连接的是哪个服务器
  • root@ubuntu1804-1:~# vim /lib/systemd/system/docker.service
    ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --label="name=docker1"
    root@ubuntu1804-2:~# vim /lib/systemd/system/docker.service
    ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --label="name=docker2"
    # 修改完配置文件都要重新加载守护进程并重启docker服务
    systemctl daemon-reload
    systemctl restart docker
    # docker info验证, 这是本机的label
     Labels:
      name=docker1
    
  • 2 让服务器端增加监听端口, 监听在当前主机任意ip地址的2375端口,常用端口
  • root@ubuntu1804-1:~# vim /lib/systemd/system/docker.service 
    ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --label="name=docker1" -H tcp://0.0.0.0:2375
    root@ubuntu1804-1:~# systemctl daemon-reload
    root@ubuntu1804-1:~# systemctl restart docker
    root@ubuntu1804-1:~# ss -ntl
    State              Recv-Q              Send-Q                            Local Address:Port                           Peer Address:Port             
    LISTEN             0                   128                               127.0.0.53%lo:53                                  0.0.0.0:*                
    LISTEN             0                   128                                     0.0.0.0:22                                  0.0.0.0:*                
    LISTEN             0                   128                                        [::]:22                                     [::]:*                
    LISTEN             0                   128                                           *:2375                                      *:* 
    # 监听了tcp端口,docker服务端就可以远程连接 
    
  • 3 实现远程连接, docker的API可以通过http://ip:port/info访问
  • [09:16:58 root@centos-7 ~]#curl http://10.0.0.239:2375/info | grep docker1
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100  2644    0  2644    0     0   153k      0 --:--:-- --:--:-- --:--:--  172k
    {"ID":"IEZZ:XGGE:CLQL:WJ4Q:V7BT:ABW3:J7CO:KQY7:QV2U:GIIW:VWXF:DK7O","Containers":1,"ContainersRunning":0,"ContainersPaused":0,"ContainersStopped":1,"Images":4,"Driver":"overlay2","DriverStatus":[["Backing Filesystem","extfs"],["Supports d_type","true"],["Native Overlay Diff","true"]],"SystemStatus":null,"Plugins":{"Volume":["local"],"Network":["bridge","host","ipvlan","macvlan","null","overlay"],"Authorization":null,"Log":["awslogs","fluentd","gcplogs","gelf","journald","json-file","local","logentries","splunk","syslog"]},"MemoryLimit":true,"SwapLimit":false,"KernelMemory":true,"KernelMemoryTCP":true,"CpuCfsPeriod":true,"CpuCfsQuota":true,"CPUShares":true,"CPUSet":true,"PidsLimit":true,"IPv4Forwarding":true,"BridgeNfIptables":true,"BridgeNfIp6tables":true,"Debug":false,"NFd":22,"OomKillDisable":true,"NGoroutines":35,"SystemTime":"2020-08-03T23:17:09.152635766+10:00","LoggingDriver":"json-file","CgroupDriver":"cgroupfs","NEventsListener":0,"KernelVersion":"4.15.0-76-generic","OperatingSystem":"Ubuntu 18.04.4 LTS","OSType":"linux","Architecture":"x86_64","IndexServerAddress":"https://index.docker.io/v1/","RegistryConfig":{"AllowNondistributableArtifactsCIDRs":[],"AllowNondistributableArtifactsHostnames":[],"InsecureRegistryCIDRs":["127.0.0.0/8"],"IndexConfigs":{"docker.io":{"Name":"docker.io","Mirrors":[],"Secure":true,"Official":true}},"Mirrors":[]},"NCPU":1,"MemTotal":2065911808,"GenericResources":null,"DockerRootDir":"/var/lib/docker","HttpProxy":"","HttpsProxy":"","NoProxy":"","Name":"ubuntu1804-1","Labels":["name=docker1"],"ExperimentalBuild":false,"ServerVersion":"19.03.12","ClusterStore":"","ClusterAdvertise":"","Runtimes":{"runc":{"path":"runc"}},"DefaultRuntime":"runc","Swarm":{"NodeID":"","NodeAddr":"","LocalNodeState":"inactive","ControlAvailable":false,"Error":"","RemoteManagers":null},"LiveRestoreEnabled":false,"Isolation":"","InitBinary":"docker-init","ContainerdCommit":{"ID":"7ad184331fa3e55e52b890ea95e65ba581ae3429","Expected":"7ad184331fa3e55e52b890ea95e65ba581ae3429"},"RuncCommit":{"ID":"dc9208a3303feef5b3839f4323d9beb36df0a9dd","Expected":"dc9208a3303feef5b3839f4323d9beb36df0a9dd"},"InitCommit":{"ID":"fec3683","Expected":"fec3683"},"SecurityOptions":["name=apparmor","name=seccomp,profile=default"],"Warnings":["WARNING: API is accessible on http://0.0.0.0:2375 without encryption.\n         Access to the remote API is equivalent to root access on the host. Refer\n         to the 'Docker daemon attack surface' section in the documentation for\n         more information: https://docs.docker.com/engine/security/security/#docker-daemon-attack-surface","WARNING: No swap limit support"]}
    
  • DOCKER_HOST环境变量 配合docker info使用
  • 如果在docker客户端定义了DOCKER_HOST变量, 则在客户端执行docker info会自动查看变量中定义的主机的docker信息
  • # 在10.0.0.239定义DOCKER_HOST为10.0.0.229, 那么执行docker info命令就会显示10.0.0.229的docker信息
    root@ubuntu-1804-1:~# export DOCKER_HOST="tcp://10.0.0.229:2375"
    root@ubuntu-1804-1:~# docker info
     Labels:
      name=docker2
    

    2 Docker基础操作

    2.1 镜像管理

    2.1.1 镜像分层

    rootfs - 基础镜像层(Centos/Ubuntu各种操作系统必要文件), 基础镜像就是没有内核的根文件系统rootfs bootfs - 启动文件系统层(当前宿主机内核)

    2.1.2 分层的优势

    分层做镜像, 作为整体使用
    基础镜像可以复用
    不同应用程序使用共同的基础镜像内容,减少磁盘使用
    镜像通过Dockerfile制作, 所以镜像本身是只读的, 除非修改Dockerfile后, 重新build镜像 而数据的更改发生在可写层, 也就是容器里 
    用户最终看到的是只读镜像层和可写层容器累计出来的综合结果
    
    root@ubuntu1804-1:~# docker pull busybox  # 如果不指名标签, 默认下载最新版本, 默认省略了busybox:latest
    Using default tag: latest
    latest: Pulling from library/busybox
    61c5ed1cbdf8: Pull complete   # 有几个pull complete那么该镜像就分了几层
    Digest: sha256:4f47c01fa91355af2865ac10fef5bf6ec9c7f42ad2321377c21e844427972977
    Status: Downloaded newer image for busybox:latest
    docker.io/library/busybox:latest
    

    2.1.3 查看镜像分层

    docker image histroy nginx  # 该命令只能查看本地已经拉取的镜像
    每一层都由命令凑起来,
    理论上,层次越少,下载内容越少,效率越高
    root@ubuntu1804-1:~# docker image history nginx
    IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
    8cf1bfb43ff5        13 days ago         /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B                   
    <missing>           13 days ago         /bin/sh -c #(nop)  STOPSIGNAL SIGTERM           0B                  
    <missing>           13 days ago         /bin/sh -c #(nop)  EXPOSE 80                    0B                  
    <missing>           13 days ago         /bin/sh -c #(nop)  ENTRYPOINT ["/docker-entr…   0B                  
    <missing>           13 days ago         /bin/sh -c #(nop) COPY file:0fd5fca330dcd6a7…   1.04kB              
    <missing>           13 days ago         /bin/sh -c #(nop) COPY file:1d0a4127e78a26c1…   1.96kB              
    <missing>           13 days ago         /bin/sh -c #(nop) COPY file:e7e183879c35719c…   1.2kB               
    <missing>           13 days ago         /bin/sh -c set -x     && addgroup --system -…   63.3MB              
    <missing>           13 days ago         /bin/sh -c #(nop)  ENV PKG_RELEASE=1~buster     0B                  
    <missing>           13 days ago         /bin/sh -c #(nop)  ENV NJS_VERSION=0.4.2        0B                  
    <missing>           13 days ago         /bin/sh -c #(nop)  ENV NGINX_VERSION=1.19.1     0B                  
    <missing>           13 days ago         /bin/sh -c #(nop)  LABEL maintainer=NGINX Do…   0B                  
    <missing>           13 days ago         /bin/sh -c #(nop)  CMD ["bash"]                 0B                  
    <missing>           13 days ago         /bin/sh -c #(nop) ADD file:6ccb3bbcc69b0d44c…   69.2MB    #基础镜像层          
    

    2.1.4 查找镜像

    docker search nginx
    

    2.1.5 镜像导出

  • 当某台服务器无法上网时, 可以找一台能连网的服务器, 把docker镜像下载下来, 然后导出为一个tar打包文件, 复制到本地服务器中
  • docker save 默认输出到标准输出, 加-o重定向
    
    [root@ubuntu-1804-1:~]# docker pull ubuntu:bionic-20200713 # 必须先拉取镜像到本地
    [root@ubuntu-1804-1:~]# docker save ubuntu:bionic-20200713 -o ubuntu1804.tar
    #也可以用标准输出重定向>来代替-o选项
    
    [root@ubuntu-1804-1:~]# scp ubuntu1804.tar 10.0.0.229:/data
    

    2.1.6 镜像导入

    docker load -i tar文件 或者 docker load < tar文件
    
    [root@ubuntu-1804-2:~]#docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    [root@ubuntu-1804-2:~]#docker load -i /data/ubuntu1804.tar 
    7ef368776582: Loading layer [==================================================>]  65.61MB/65.61MB
    83f4287e1f04: Loading layer [==================================================>]  991.7kB/991.7kB
    d3a6da143c91: Loading layer [==================================================>]  15.87kB/15.87kB
    8682f9a74649: Loading layer [==================================================>]  3.072kB/3.072kB
    Loaded image: ubuntu:bionic-20200713
    [root@ubuntu-1804-2:~]#docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    ubuntu              bionic-20200713     2eb2d388e1a2        2 months ago        64.2MB
    

    2.1.7 Overlay2联合文件存储驱动

    overlay2是联合文件系统存储驱动的默认方式, 可通过docker info查看方式
    
  • 下载的docker文件都是放在/var/lib/docker目录下
  • 镜像和容器的数据都是存放在/var/lib/docker/overlay2目录里, 可以通过docker inspect 镜像id/容器id查看"Data"下的目录信息, 来确定镜像或者容器数据的存放位置.
  • 镜像拉取后, 会生成以Hash值命名的目录, 启动容器后也会生成以Hash值命名的目录. 通过同一个镜像启动的不同容器的目录名称是不同的. 镜像和以该镜像为模版启动的容器的目录名称也是不同的。
  •             "Data": {
                    "MergedDir": "/var/lib/docker/overlay2/b2b440091491c2d19faaaf24d4a008a36adf8d75d416c1ca71bc40bc8fbc32ec/merged",
                    "UpperDir": "/var/lib/docker/overlay2/b2b440091491c2d19faaaf24d4a008a36adf8d75d416c1ca71bc40bc8fbc32ec/diff",
                    "WorkDir": "/var/lib/docker/overlay2/b2b440091491c2d19faaaf24d4a008a36adf8d75d416c1ca71bc40bc8fbc32ec/work"
    
  • 而/var/lib/docker/containers目录下的不同目录内的数据是容器启动时创建的, 包含对应容器的一些基本信息
  • 容器的主机名
    容器的ip
    容器的DNS
    
  • 一个镜像会分开保存在磁盘不同的目录里, 可通过docker inspect查看具体保存的位置
  • 不同镜像 不同容器 目录不同
  • 同一镜像 不同容器 目录不同
  • root@ubuntu1804-1:~# du -sh /var/lib/docker/*
    20K /var/lib/docker/builder
    72K /var/lib/docker/buildkit
    44K /var/lib/docker/containers
    1.7M    /var/lib/docker/image
    52K /var/lib/docker/network
    445M    /var/lib/docker/overlay2
    20K /var/lib/docker/plugins
    4.0K    /var/lib/docker/runtimes
    4.0K    /var/lib/docker/swarm
    4.0K    /var/lib/docker/tmp
    4.0K    /var/lib/docker/trust
    28K /var/lib/docker/volumes
    root@ubuntu1804-1:~# du -sh /var/lib/docker/overlay2/*
    1.3M    /var/lib/docker/overlay2/0e729c7b739cb15ed94f14942320c8098cd51835ae521c2a1eea61fb53ce6b20
    1000K   /var/lib/docker/overlay2/114a54a438da42e6e26dc26416f9fc1595e9dff4a654bd0e13ec8597bb6ca83e
    229M    /var/lib/docker/overlay2/13df551e2977c6046386a0a54160ce8429b4052efc7097c4471c591058a8f73c
    69M /var/lib/docker/overlay2/1dd163494d5163f84e24ffba0b41c578040b7fd8f644b589174cc630de77ba56
    28K /var/lib/docker/overlay2/34061f8bae516feb1308580c75259aeac41f06740dc58d74bcd99bf4fcd351c5
    76M /var/lib/docker/overlay2/3da244b30449d90d19f7aa2e7925bdc684418e391f95c22799a68c94e7565ca9
    36K /var/lib/docker/overlay2/43726bbfedfcad3d9f2379dc92544606437146d7081f6ef0957813d5fdde29cb
    24K /var/lib/docker/overlay2/78efa5af3b8d6634602109d8b1211d4624dd9a734cb2f486c06e86a4ace26cbc
    48K /var/lib/docker/overlay2/78efa5af3b8d6634602109d8b1211d4624dd9a734cb2f486c06e86a4ace26cbc-init
    28K /var/lib/docker/overlay2/809fa29d2578da5c6762eea655306e28778b9b53c4c1d8b649c5902a048a585f
    6.0M    /var/lib/docker/overlay2/87c6278a2d1903f487944dde9cd6afebaac95f25af0d527e0550b44b1c79322a
    24K /var/lib/docker/overlay2/887f6295f34bd0997b63f4177ba728a9232cfbee0e367287934f511ccc71d542
    28K /var/lib/docker/overlay2/a98a3437396ce469ee8693281655168a75be7d8a4882f23a4c4a39b98261f734
    64M /var/lib/docker/overlay2/cf6bda03ff1c59a5f87470fb75ea27e171a6a5a31af5cb271a5fa4f66455f184
    100K    /var/lib/docker/overlay2/f9dbae88840c1abb57a52fed8ca027a22bd81b114fb355b6e80f5963a32793c4
    64K /var/lib/docker/overlay2/
    # 镜像的每一层都是哈希值来表示, 不同的哈希值代表不同的镜像层, 用以区分是否为相同的镜像层
    

    2.1.8 删除镜像

  • docker rmi 镜像id , 写前几位不同的id即可, 能唯一标示一个id就可以
  • [root@ubuntu-1804-2:~]#docker rmi 2eb2d388e1a2
    Untagged: ubuntu:bionic-20200713
    Deleted: sha256:2eb2d388e1a255c98029f40d6d7f8029fb13f1030abc8f11ccacbca686a8dc12
    Deleted: sha256:48ba0c6fdf4b069aad7a1eb6299dee017ef75b929a87ed63bc9226dee2cd50e8
    Deleted: sha256:4d5330c8d5056fdfb6f2e32b225452de71517794a80e3ef998440e184d2e80cb
    Deleted: sha256:3a9fa6b9e7ae21b704ed61109b612970f2b21449cd53e3154ed8800e2aefee0d
    Deleted: sha256:7ef3687765828a9cb2645925f27febbac21a5adece69e8437c26184a897b6ec7
    # 注意, 这里显示的sha256哈希值和/var/lib/docker/overlay2里存放的镜像哈希值不一样
    
  • 一次删除所有镜像
  • docker images -q 查看镜像id

    root@ubuntu1804-1:~# docker images -q
    018c9d7b792b
    2eb2d388e1a2
    8cf1bfb43ff5
    a24bb4013296
    
    root@ubuntu1804-1:~# docker images -q
    018c9d7b792b
    2eb2d388e1a2
    8cf1bfb43ff5
    a24bb4013296
    root@ubuntu1804-1:~# docker images -q | xargs 
    018c9d7b792b 2eb2d388e1a2 8cf1bfb43ff5 a24bb4013296
    root@ubuntu1804-1:~# docker images -q | xargs docker rmi 
    Untagged: busybox:latest
    Untagged: busybox@sha256:4f47c01fa91355af2865ac10fef5bf6ec9c7f42ad2321377c21e844427972977
    Deleted: sha256:018c9d7b792b4be80095d957533667279843acf9a46c973067c8d1dff31ea8b4
    Deleted: sha256:514c3a3e64d4ebf15f482c9e8909d130bcd53bcc452f0225b0a04744de7b8c43
    Untagged: ubuntu:bionic-20200713
    Untagged: ubuntu@sha256:a61728f6128fb4a7a20efaa7597607ed6e69973ee9b9123e3b4fd28b7bba100b
    Deleted: sha256:2eb2d388e1a255c98029f40d6d7f8029fb13f1030abc8f11ccacbca686a8dc12
    Deleted: sha256:48ba0c6fdf4b069aad7a1eb6299dee017ef75b929a87ed63bc9226dee2cd50e8
    Deleted: sha256:4d5330c8d5056fdfb6f2e32b225452de71517794a80e3ef998440e184d2e80cb
    Deleted: sha256:3a9fa6b9e7ae21b704ed61109b612970f2b21449cd53e3154ed8800e2aefee0d
    Deleted: sha256:7ef3687765828a9cb2645925f27febbac21a5adece69e8437c26184a897b6ec7
    Untagged: nginx:latest
    Untagged: nginx@sha256:0632aa5183f266cf1b7272ab120f3fb7fe06fae6bf74a734de51590a6ef44cbe
    Deleted: sha256:8cf1bfb43ff5d9b05af9b6b63983440f137c6a08320fa7592197c1474ef30241
    Deleted: sha256:f693fa68e7be60da5f2631f94268bb7231278a9e0a10e25798173ce6dd2e4d9d
    Deleted: sha256:ed095e8a33da1985dfdb0b098c2e7ffb035f98f2ff98c648bdf67d4b880a7b3d
    Deleted: sha256:3a069d285e939b95a82cecf0e6ac9b3ac3c21397f9d1c97276f98551cfa02b3d
    Deleted: sha256:18cb14912446a24695198924710f359397929d94acd7d86c8bb0b3dbaa9b672f
    Deleted: sha256:95ef25a3204339de1edf47feaa00f60b5ac157a498964790c58c921494ce7ffd
    Untagged: alpine:latest
    Untagged: alpine@sha256:185518070891758909c9f839cf4ca393ee977ac378609f700f60a771a2dfe321
    Deleted: sha256:a24bb4013296f61e89ba57005a7b3e52274d8edd3ae2077d04395f806b63d83e
    Deleted: sha256:50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a
    root@ubuntu1804-1:~# docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    
  • 不能用通配符*, 因为表示*的是当前目录下文件和目录
  • 另一种删除所有镜像方法

    root@ubuntu1804-1:~# docker rmi `docker images -q`
    Untagged: busybox:latest
    Untagged: busybox@sha256:4f47c01fa91355af2865ac10fef5bf6ec9c7f42ad2321377c21e844427972977
    Deleted: sha256:018c9d7b792b4be80095d957533667279843acf9a46c973067c8d1dff31ea8b4
    Deleted: sha256:514c3a3e64d4ebf15f482c9e8909d130bcd53bcc452f0225b0a04744de7b8c43
    Untagged: alpine:latest
    Untagged: alpine@sha256:185518070891758909c9f839cf4ca393ee977ac378609f700f60a771a2dfe321
    Deleted: sha256:a24bb4013296f61e89ba57005a7b3e52274d8edd3ae2077d04395f806b63d83e
    Deleted: sha256:50644c29ef5a27c9a40c393a73ece2479de78325cae7d762ef3cdc19bf42dd0a
    
  • 如果镜像已经运行加载到内存变成了容器, 那么删除时需要加-f选项, 否则无法删除
  • 建立别名, 方便删除所有镜像

    root@ubuntu1804-1:~# echo 'alias rmimage="docker images -q | xargs docker rmi -f"' >> .bashrc 
    root@ubuntu1804-1:~# . .bashrc
    root@ubuntu1804-1:~# alias
    alias egrep='egrep --color=auto'
    alias fgrep='fgrep --color=auto'
    alias grep='grep --color=auto'
    alias l='ls -CF'
    alias la='ls -A'
    alias ll='ls -alF'
    alias ls='ls --color=auto'
    alias rmimage='docker images -q | xargs docker rmi
    

    2.1.9 给镜像打标签, 通常用于说明镜像的版本号

    root@ubuntu1804-2:~# docker pull busybox
    root@ubuntu1804-2:~# docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    busybox             latest              018c9d7b792b        7 days ago          1.22MB
    root@ubuntu1804-2:~# docker tag 018c9d7b792b busybox:v3.12.0
    root@ubuntu1804-2:~# docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
    busybox             latest              018c9d7b792b        7 days ago          1.22MB
    busybox             v3.12.0             018c9d7b792b        7 days ago          1.22MB
    #贴标签后,会生成额外一个带有相同id的镜像列表,但是只是列表并不是生成另一个镜像文件
    #只不过起了个标签,实际对应的是同一个东西,类似硬链接
    #下载和删除镜像时,如果没指定版本,那么默认下载和删除的都是最新版
    #打完标签可以把latest的删除 docker rmi busybox 默认删除最新版
    #如果想删除所有相同id的镜像, 可以 docker rmi -f IMAGE-ID, 不加-f选项不让同时删除id相同的所有镜像
    

    2.2 容器操作基础命令

    docker 命令为了方便学习管理, 针对镜像, 容器, 卷, 网络等不同资源把命令分类整理
    Manage Command指明了该命令是用来管理哪些资源的, 每个资源里还有子命令, 实现具体操作
    

    2.2.1 启动容器

    docker run  = docker container run
    
    运行本地没有的镜像时, 会自动到docker hub上去拉镜像
    docker run进行的操作:
    1. 把镜像复制一份形成新的容器文件
    2. 把容器文件加载到内存运行, 并且随机分配一个container id, 16进制, 同时还会分配一个容器名称
    
  • 查看运行的容器
  • docker ps = docker container ls

    root@ubuntu1804-1:~# docker ps
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    
  • 查看所有容器
  • root@ubuntu1804-1:~# docker ps -a
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
    f0bbcbe4b92a        hello-world         "/hello"            3 minutes ago       Exited (0) 3 minutes ago                       magical_tu
    34eddd6df328        hello-world         "/hello"            10 days ago         Exited (0) 10 days ago                         flamboyant_lewin
    
  • 查看运行中的容器ID
  • docker ps -q 
    

    2.2.2 删除容器

    docker rm -f 容器ID
    

    -f 选项是强行删除, 否则如果容器正在运行是不能删除的

  • 删除所有容器
  • docker rm -f   `docker ps -qa`
    

    2.2.3 指定容器启动后执行的命令

  • 每个镜像都有启动后, 默认自动执行的命令

  • 如果启动后, 默认执行的命令就是一个普通命令, 那么当该命令执行完, 该容器就会自动关闭, 进入Exited状态. 不过容器退出后还会在磁盘保存

  • 只有运行了持续在前台运行的命令的容器才会一直保持运行状态

  • 用户也可以指定启动镜像后, 执行什么命令, 不过需要镜像支持该命令. 因为镜像的底层就是一个小的操作系统, 因此想执行什么命令, 需要操作系统本身支持才行

  • root@ubuntu1804-1:~# docker run alpine uname -a 
    Linux 7efaa79dff31 4.15.0-76-generic #86-Ubuntu SMP Fri Jan 17 17:24:28 UTC 2020 x86_64 Linux
    root@ubuntu1804-1:~# uname -a
    Linux ubuntu1804-1 4.15.0-76-generic #86-Ubuntu SMP Fri Jan 17 17:24:28 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
    #容器是用的宿主机内核, 所以uname -a显示的内核就是宿主机的内核信息
    #7efaa79dff31是容器主机名, 是启动容器时随机生成的, 可以通过docker ps -a看到
    root@ubuntu1804-1:~# docker ps -a
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
    7efaa79dff31        alpine              "uname -a"          42 seconds ago      Exited (0) 41 seconds ago                       relaxed_shaw
    
    root@ubuntu1804-1:~# docker run alpine cat /etc/os-release
    NAME="Alpine Linux"
    ID=alpine
    VERSION_ID=3.12.0
    PRETTY_NAME="Alpine Linux v3.12"
    HOME_URL="https://alpinelinux.org/"
    BUG_REPORT_URL="https://bugs.alpinelinux.org/"
    
    #alpine启动默认运行的命令是/bin/sh, 而/bin/sh是后台运行的命令, 所以alpine启动后, 执行完/bin/sh, 就会自动退出, 进入Exited状态
    root@ubuntu1804-1:~# docker ps -a
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                     PORTS               NAMES
    49e352789c8c        alpine              "/bin/sh"           8 seconds ago       Exited (0) 7 seconds ago                       recursing_dewdney
    
    在容器中, 如果系统发现容器内没有前台执行的进程,那么系统就会认为容器是退出的状态,会关掉容器
    镜像就是除了bootfs的一个精简的rootfs
    写实复制: 多次docker run同一个镜像时, 会生成多个容器, 多个容器共用一个镜像层, 数据的更改发生在容器层, 并不是运行一个容器就会复制一份镜像文件
    所以, 当连续从同一个镜像启动多个容器后, 虽然可以看到每个容器都占有相同的空间大小(docker ps -as), 但是宿主机的/var/lib/docker/overlayr2目录的大小是几乎不变的, 因为多个容器都是基于同一个镜像启动的, 并不会每启动一个容器, 就会复制一次镜像, 专门给该容器使用
    

    2.2.4 给容器起别名

    不能给正在运行或者已经退出的容器起别名
    
    root@ubuntu1804-1:~# docker run --name b1 busybox
    

    2.2.5 容器执行完成退出后自动删除

    root@ubuntu1804-1:~# docker run --rm --name b3 busybox
    #删除后无法通过docker ps -a看到, 因为该命令只显示处于运行和退出状态的容器
    

    2.2.6 运行并且进入容器

  • -i 选项, 交互式
  • -t 选项, 系统自动分配一个终端
  • i和t搭配一起使用,
  • root@ubuntu1804-1:~# docker run -it --name a11 alpine 
    # 进入到了容器后是不会自动退出的, 容器会处于运行状态
    root@ubuntu1804-1:~# docker ps 
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    a3d40adbd424        alpine              "/bin/sh"           15 seconds ago      Up 14 seconds                           a11
    
    root@ubuntu-1804-19:~# docker ps -a
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    72f3b0f4e279        busybox             "sh"                5 minutes ago       Up 5 minutes                            b1
    root@ubuntu-1804-19:~# docker run --rm -it --name a1 alpine  # --rm和-it搭配使用, 会先进入容器. 一旦退出, 那么就会自动把容器删除
    / # ls
    bin    dev    etc    home   lib    media  mnt    opt    proc   root   run    sbin   srv    sys    tmp    usr    var
    / # exit
    root@ubuntu-1804-19:~# docker ps -a
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    72f3b0f4e279        busybox             "sh"                5 minutes ago       Up 5 minutes                            b1
    

    2.2.7 容器退出

  • exit 退出 会退出容器, 但是不删除, docker ps -a中是Exited状态
  • /etc # exit
    root@ubuntu1804-1:~# 
    root@ubuntu1804-1:~# docker ps -a
    CONTAINER ID        IMAGE               COMMAND                 CREATED             STATUS                          PORTS               NAMES
    a3d40adbd424        alpine              "/bin/sh"               5 minutes ago       Exited (0) About a minute ago                       a11
    
  • 退出容器时不停止容器, 让容器继续运行
  • ctrl+p+q

    root@ubuntu1804-1:~# docker run -it --name a12 alpine 
    / # ls
    bin    dev    etc    home   lib    media  mnt    opt    proc   root   run    sbin   srv    sys    tmp    usr    var
    / # root@ubuntu1804-1:~# 
    root@ubuntu1804-1:~# docker ps
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    773d617d3548        alpine              "/bin/sh"           19 seconds ago      Up 18 seconds                           a12
    

    之后想再进入容器, 需要使用exec

    root@ubuntu1804-1:~# docker exec -it 77 sh
    

    2.2.8 守护式容器

  • 能够长期运行
  • 无需进入交互式终端
  • 适合运行应用程序和服务
  • 守护式容器, 默认在终端前台运行, 用ctrl+c会退出容器, 也可以人为指定容器在后台运行, 只需启动时, 添加-d选项
  • 如果想要容器启动后, 不退出, 那么在容器启动时, 就要执行一个能占据前台终端的命令
    如果想要该容器不占据前台终端, 并且能够持续运行, 那么就要在启动时再添加-d选项
    

    docker run nginx 运行后容器会在前台执行

    10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf
    10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
    /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
    /docker-entrypoint.sh: Configuration complete; ready for start up
    root@ubuntu1804-1:~# docker ps
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
    a316e78bdb37        nginx               "/docker-entrypoint.…"   6 seconds ago       Up 5 seconds        80/tcp              brave_kepler
    

    docker inspect 容器ID或者容器名字来查看容器信息, ip等

    在同一个宿主机运行的容器, 默认是可以通讯的, 因为宿主机安装docker后, 会生成一个桥接网卡docker0, 用于
    1: 宿主机内的容器间通讯
    2: 容器和宿主机通讯
    3: 容器和外界互联网通讯, SNAT
    4: 容器和其他宿主机的通讯, SNAT
    不同宿主机内运行的容器, 默认不能通讯
    外部的服务器和容器无法直接访问另一台宿主机内的容器
    
    root@ubuntu-1804-19:~# ip a
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
        inet6 ::1/128 scope host 
           valid_lft forever preferred_lft forever
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
        link/ether 00:0c:29:49:4c:e1 brd ff:ff:ff:ff:ff:ff
        inet 10.0.0.19/24 brd 10.0.0.255 scope global eth0
           valid_lft forever preferred_lft forever
        inet6 fe80::20c:29ff:fe49:4ce1/64 scope link 
           valid_lft forever preferred_lft forever
    3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
        link/ether 02:42:83:76:7e:37 brd ff:ff:ff:ff:ff:ff
        inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
           valid_lft forever preferred_lft forever
        inet6 fe80::42:83ff:fe76:7e37/64 scope link 
           valid_lft forever preferred_lft forever
    27: veth5f13a91@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
        link/ether b6:92:cd:f3:da:79 brd ff:ff:ff:ff:ff:ff link-netnsid 0
        inet6 fe80::b492:cdff:fef3:da79/64 scope link 
           valid_lft forever preferred_lft forever
    
    root@ubuntu-1804-19:~# docker ps -a
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
    938ede4058fc        nginx               "/docker-entrypoint.…"   6 minutes ago       Up 6 minutes        80/tcp              great_wright
    root@ubuntu-1804-19:~# docker inspect 938ede4058fc | grep -i ip
    "IPAddress": "172.17.0.2",
    
    # 宿主机可以访问容器
    root@ubuntu-1804-19:~# curl 172.17.0.2
    <!DOCTYPE html>
    <title>Welcome to nginx!</title>
    <style>
    html { color-scheme: light dark; }
    body { width: 35em; margin: 0 auto;
    font-family: Tahoma, Verdana, Arial, sans-serif; }
    </style>
    </head>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>
    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>
    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>
    
    # 来自宿主机的访问日志
    172.17.0.1 - - [23/Oct/2022:12:42:55 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.58.0" "-"
    172.17.0.1 - - [23/Oct/2022:12:43:39 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.58.0" "-"
    
    # 同一个宿主机内部的容器是可以互相通信的
    root@ubuntu-1804-19:~# docker ps -a
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
    938ede4058fc        nginx  # (正在运行的nginx容器)             "/docker-entrypoint.…"   14 minutes ago      Up 14 minutes       80/tcp              great_wright
    root@ubuntu-1804-19:~# docker run -it --name b1 busybox # 在同一个宿主机上启动另一个容器
    / # wget 172.17.0.2
    Connecting to 172.17.0.2 (172.17.0.2:80)
    saving to 'index.html'
    index.html           100% |*********************************************************************************************|   615  0:00:00 ETA
    'index.html' saved
    
    172.17.0.3 - - [23/Oct/2022:12:49:31 +0000] "GET / HTTP/1.1" 200 615 "-" "Wget" "-"
    
    # VMware运行在Windows系统上, 那么Windows系统相对于运行容器的宿主机来说, 就是外部的服务, 是无法直接访问到宿主机内部运行的容器的
    

    作测试时运行容器可以加--rm选项, 容器退出时会自动删除

    容器如果运行在前台,那么摁了ctrl+c就会退出, 所以需要让容器运行在后台
    对于守护式进程,比如nginx这些服务进程, 需要让他们在后台持续运行, 不占用终端资源
    
    root@ubuntu1804-1:~# docker run -d nginx
    133b5933f9255ed3b9a98cc9197aed658a31a689905bd5d8168e280ba7085c90
    root@ubuntu1804-1:~# docker ps 
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
    133b5933f925        nginx               "/docker-entrypoint.…"   49 seconds ago      Up 48 seconds       80/tcp              kind_swirles
    -d 选项会让容器在后台运行,不加-d则在前台运行
    因为nginx是守护式容器, 启动后会自动执行在前台运行的命令, 这样会占用终端而且一旦摁了ctrl+c容器就会退出了
    

    使用-d选项, 这时即使容器在后台运行也不会退出, 因为nginx容器在启动时会在前台运行nginx命令

                "Cmd": [
                    "nginx",
                    "-g",
                    "daemon off;"  # 关闭守护进程, 将nginx命令运行在前台
    

    -d 选项, 是让容器在终端后台运行, 但是容器内必须有一个进程是在前台运行的才可以, 否则开启就会自动退出了, 这里daemon off指的是, nginx在容器中运行是以前台运行命令, 只不过运行容器时加了-d选项, 让容器本身在后台运行了, 为了不占用终端资源, 也防止有人ctrl+c把容器停了

    业务类容器和守护进程式容器 开启后除非手动关闭否则不会自动退出
    基础操作系统容器开启会自动退出, 因为没有前台命令一直执行. 即使运行容器时加了-d选项, 让容器在后台运行, 但是因为没有能在前台运行的命令, 因此也会开启后自动退出
    
    只有服务类软件的容器 才是守护进程容器, 因为有可以在前台执行的程序, 比如nginx
    

    docker ps -l 显示最近启动的容器

  • 基础镜像容器运行时可以用-td选项, 这样会在启动容器时分配一个终端, 保持前台运行, 防止启动后自动退出, 因为基础镜像启动后是没有前台运行的命令的
  • [root@ubuntu-1804-1:~]# docker run -td --name alpine111 alpine
    49a7ab318eb93ff69f6e8b9543af64bba1cc89e7d465d3ed55f4c4c7a34405cc
    [root@ubuntu-1804-1:~]# docker ps
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    49a7ab318eb9        alpine              "/bin/sh"           6 seconds ago       Up 5 seconds                            alpine111
    
  • 设置容器开机自启或者是一旦停了就自动重启
    默认情况下, 容器不会随着宿主机启动而自动启动
  • --restart=always 选项使得容器随着宿主机启动而自动启动,或者容器一旦退出就自动重启
    root@ubuntu1804-1:~# docker run -d --name NGINX --restart=always nginx
    b956aaefd3fed0bd93258dcd31eb3a2f5ae4939b6caffd227dc89c2461ab5f05
    
    root@ubuntu-1804-19:~# reboot
    Connection closed by foreign host.
    root@ubuntu-1804-19:~# docker ps  # NGINX镜像会随着系统启动而自动启动
    CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS               NAMES
    ee24db501fd7        nginx               "/docker-entrypoint.…"   About a minute ago   Up 25 seconds       80/tcp              NGINX
    
    root@ip-172-31-45-152:~# docker run -it --name a1 alpine
    / # exit
    root@ip-172-31-45-152:~# docker ps -a
    CONTAINER ID   IMAGE     COMMAND     CREATED         STATUS                    PORTS     NAMES
    ae1be52d67ba   alpine    "/bin/sh"   3 seconds ago   Exited (0) 1 second ago             a1
    
    root@ip-172-31-45-152:~# docker run -it --name a2 --restart=always  alpine
    / # exit
    root@ip-172-31-45-152:~# docker ps -a # a2容器会在退出后, 自动重启
    CONTAINER ID   IMAGE     COMMAND     CREATED          STATUS                      PORTS     NAMES        
    100b181ec00e   alpine    "/bin/sh"   3 seconds ago    Up 1 second                           a2
    ae1be52d67ba   alpine    "/bin/sh"   36 seconds ago   Exited (0) 34 seconds ago             a1
    
  • 删除全部容器
  • root@ubuntu1804-1:~# docker ps -aq | xargs docker rm -f
    root@ubuntu1804-1:~# docker rm -f `docker ps -aq`
    -a 全部容器, 包括正在运行的和退出的
    -q 只显示容器id
    

    进入到容器后执行df或者lsblk显示的是宿主机的分区信息

    宿主机的分区信息是属于硬盘资源, 默认在容器内部是看不到宿主机硬盘的挂载点的, 只能看到宿主机的硬盘分区情况(sda, sda1, sda2, sda3, sda4...)以及容器内的挂载点情况, 所以也就无法从容器内访问宿主机的挂载点来查看硬盘分区里的内容
    因此, 可以将硬盘分区, 挂载到容器内的目录, 这样就可以在容器里访问和管理硬盘分区的内容了

    root@ubuntu-1804-19:~# docker run -it --name u1 ubuntu
    

    此时是无法将宿主机磁盘挂载到容器里某个目录下的
    因此, 在容器环境里的root是只能管理容器内部的资源的, 无法管理宿主机的资源

    root@59498b24b2b8:/# lsblk
    NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
    sda      8:0    0   50G  0 disk 
    |-sda1   8:1    0 18.6G  0 part /etc/hosts
    |                               /etc/hostname
    |                               /etc/resolv.conf
    |-sda2   8:2    0  954M  0 part 
    |-sda3   8:3    0    1K  0 part 
    |-sda4   8:4    0 28.6G  0 part 
    `-sda5   8:5    0  1.9G  0 part [SWAP]
    sr0     11:0    1  921M  0 rom  
    root@59498b24b2b8:/# ls /mnt             
    root@59498b24b2b8:/# mount /dev/sda3 /mnt
    mount: /mnt: permission denied.
    
  • 运行容器时,添加--privileged 选项使得容器里的root账户也能管理宿主机资源
  • root@ubuntu-1804-19:~# docker run -it --privileged --name u2 ubuntu
    root@4fdfb823be5f:/# ls /mnt
    root@4fdfb823be5f:/# lsblk
    NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
    sda      8:0    0   50G  0 disk 
    |-sda1   8:1    0 18.6G  0 part /etc/hosts
    |                               /etc/hostname
    |                               /etc/resolv.conf
    |-sda2   8:2    0  954M  0 part 
    |-sda3   8:3    0    1K  0 part 
    |-sda4   8:4    0 28.6G  0 part 
    `-sda5   8:5    0  1.9G  0 part [SWAP]
    sr0     11:0    1  921M  0 rom  
    root@4fdfb823be5f:/# mount /dev/sda4 /mnt
    root@4fdfb823be5f:/# ls /mnt
    lost+found  pkgs  prac  scripts
    

    此时在容器内, 可以看到宿主机上的资源, 我的宿主机上sda4是挂载到了/data目录下
    此时在容器里ls /mnt也能看到和/data里相同的内容
    并且在容器里可以删除sda4里的内容
    相当于sda4分别挂载到了宿主机/data和容器/mnt里, 并且在这两个目录内做的操作会直接影响宿主机sda4信息

    加了--priviledged选项, 那么此容器的root就具有宿主机管理员权限了
    即使在宿主机上创建000权限文件,在容器内也能删除

    root@ubuntu-1804-19:~# cd /data
    root@ubuntu-1804-19:/data# touch docker.txt
    root@ubuntu-1804-19:/data# chmod 000 docker.txt 
    root@ubuntu-1804-19:/data# ll docker.txt 
    ---------- 1 root root 0 Oct 23 21:53 docker.txt
    root@4fdfb823be5f:/# cd /mnt
    root@4fdfb823be5f:/mnt# ls
    docker.txt  lost+found  pkgs  prac  scripts
    root@4fdfb823be5f:/mnt# echo 123 > docker.txt 
    root@4fdfb823be5f:/mnt# cat docker.txt 
    root@4fdfb823be5f:/mnt# rm -rf docker.txt 
    root@4fdfb823be5f:/mnt# ls
    lost+found  pkgs  prac  scripts
    root@ubuntu-1804-19:/data# ls
    lost+found  pkgs  prac  scripts
    

    慎用--privileged: 避免容器内的root, 错误的修改了宿主机的资源

  • 查看容器中的进程
  • 利用docker top 容器名字或者ID命令, 查看正在运行的容器中的进程,  因为只有运行的容器才会生成进程
    
    但是 该命令所显示的PID是宿主机上的进程id
    而在容器内进程id就是1 因为一个容器就是一个小的操作系统并且只跑一个程序 所以每个进程都认为该系统只有自己在运行
    所以容器实际就是一个操作系统进程 最终都要跑在宿主机操作系统上
    Vmware虚拟机里跑的进程在Windows宿主机是看不到的 容器里的进程在宿主机可以看到
    所以虚拟机里的进程和系统硬件之间还隔了一层虚拟机管理系统
    但是容器里的进程直接跑在宿主机硬件上 性能好 没有损耗
    
    root@4fdfb823be5f:/mnt# ps aux
    USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    root          1  0.0  0.0   4624  3816 pts/0    Ss   13:51   0:00 bash
    root         20  0.0  0.0   7056  1556 pts/0    R+   14:17   0:00 ps aux
    
    root@ubuntu-1804-19:/data# docker ps 
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    4fdfb823be5f        ubuntu              "bash"              23 minutes ago      Up 23 minutes                           u2
    59498b24b2b8        ubuntu              "bash"              26 minutes ago      Up 26 minutes                           u1
    root@ubuntu-1804-19:/data# docker top 4fdfb823be5f
    UID                 PID                 PPID                C                   STIME               TTY                 TIME                CMD
    root                22637               22606               0                   21:51               pts/0               00:00:00            bash
    root@ubuntu-1804-19:/data# ps aux | grep 22637
    root      22637  0.0  0.0   4624  3816 pts/0    Ss+  21:51   0:00 bash
    root      22811  0.0  0.0  14428  1048 pts/2    S+   22:14   0:00 grep --color=auto 22637
    root@ubuntu-1804-19:/data# ps aux | grep 22606
    root      22606  0.0  0.1 709996  7800 ?        Sl   21:51   0:00 containerd-shim -namespace moby -workdir /var/lib/containerd/io.containerd.runtime.v1.linux/moby/4fdfb823be5f2bb7b643259a251ff66f875aaf1bbc647d3a6a75ff8ede6e9c99 -address /run/containerd/containerd.sock -containerd-binary /usr/bin/containerd -runtime-root /var/run/docker/runtime-runc
    root      22813  0.0  0.0  14428  1052 pts/2    R+   22:14   0:00 grep --color=auto 22606
    
  • 容器和vmware区别
  • 容器并不虚拟化硬件, 而是直接跑在操作系统硬件上
    容器虚拟出来的是一个没有内核的小的操作系统, 只有基本的根文件系统, 网络空间, 用户id等
    默认容器是可以使用宿主机全部资源的 因此一个容器很可能用光宿主机所有内存
    所以需要对容器做资源限制
    
  • docker stats 容器id或名字
  • 查看容器资源使用情况, 默认容器是没有资源使用限制的
    一般的进程直接跑在服务器上是不容易限制资源的, 但是容器可以限制资源, 也是容器好处之一

    root@ubuntu-1804-19:/data# docker stats 4fdfb823be5f
    CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT    MEM %               NET I/O             BLOCK I/O           PIDS
    4fdfb823be5f        u2                  0.00%               2.375MiB / 3.83GiB(容器默认可以使用宿主机所有资源, 包括内存, 所以这里是接近4G的内存限制, 因为此时宿主机的内存是4G)   0.06%               1.08kB / 0B         1.05MB / 4.1kB      1
    

    2.2.9 容器的启动和暂停

    docker start|stop|restart|pause|unpause  容器ID
    docker start 
    docker stop nginx(写容器ID或者容器名字) 相当于杀死nginx进程 docker ps或者dockers top都看不到了, 容器会进入Exited状态
    docker pause nginx 挂起nginx, 挂起后, 容器在宿主机的进程状态显示为D, 通过 ps aux 还能看到 显示为进程标识ID, 可以被从重新唤醒
    docker unpause nginx, 唤醒
    --restart 可以指定四种不同的policy: always策略可以提供简单的故障恢复功能, 当容器退出时会自动重启.
    no: Default is no,Do not automatically restart the container when it exits.
    on-failure[:max-retries]: on-failure[:max-retries] Restart only if the container exits with a non-zero exit status. Optionally, limit the number of restart retries the Docker
    daemon attempts.
    always: Always restart the container regardless of the exit status. When you specifyalways, the Docker daemon will try to restart the container indefinitely. The container will also always start on daemon startup, regardless of the current state of the container.
    unless-stopped: Always restart the container regardless of the exit status, but do not start iton daemon startup if the container has been put to a stopped state before.

    2.2.10 给正在运行的容器发信号 - kill

    docker kill 默认发-9 信号
    docker -s 指定信号
    

    2.2.11 进入正在运行的容器

    守护类容器, 启动时需要用-d选项, 此时即使用了-it进入交互式, 也不会真的进入容器, 还需要之后用exec或者attach进入正在运行的容器

    root@ubuntu-1804-19:/data# docker run -d -it --name n1 nginx
    9ab8f94ef91596ab0358de624d6e90293ef6f789adca7c02f312240439bcd622
    

    2.2.11.1 exec

    exec 进入运行中的容器并执行命令, 也可以进入容器或者不进入容器只执行命令 并且执行exit退出时容器会继续运行
    多个终端利用exec进入同一个容器时 互不影响 不会看到其他终端的操作
    
    交互进入容器: docker exec -it 4f bash #需要标明进入容器后执行的命令 #Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...], 如果不指定命令, 会提示报错
    非交互临时运行命令: docker exec 4f cat /etc/os-release
    root@ubuntu-1804-19:~# 
    root@ubuntu-1804-19:~# docker ps
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
    9ab8f94ef915        nginx               "/docker-entrypoint.…"   11 minutes ago      Up 10 minutes       80/tcp              n1
    

    2.2.11.2 attach

    attach 多个终端进入同一个容器会相互影响 并且exit退出时 容器会exit停止运行
    不安全 终端的操作可以被看见, 每个终端显示的内容是一样的
    不靠谱 exit退出时 容器就停止运行了
    只想退出当前终端容器, 并且退出容器后容器不停止, 需要用ctrl+p+q 
    

    2.2.12 容器的网络

    容器只有启动后才会得到系统资源, 网络,内存等, 容器停掉后系统会回收资源
    因此每次分配的资源, 有可能是不同的
    安装了docker-ce后, 会生成一个桥接网卡, docker0, 每个宿主机的docker0都是172.17.0.1/16的地址. 
    默认不同宿主机之间, 容器是不能通信的. 一个宿主机内的容器和其他宿主机可以通信
    外界宿主机和容器都无法直接访问另一台宿主机内的容器
    

    同一宿主机的不同容器是如何通信的?

    image.png

    桥接网卡docker0就相当于一个交换机, 因此, 同一个宿主机内的容器, 是可以通信的, 因为网关都指向了桥接网卡, 相当于都桥接在了docker 0上. 因此, 可以通信

    容器启动后宿主机系统会生成虚拟网卡vethxxxx 用于宿主机和容器通信, 这个虚拟网卡相当于把一个网卡分成两半, 一半接在了docker0桥接网卡上, 一半是在容器的eth0上, 容器中的网卡eth0 和 宿主机的docker 0 网卡是靠这个桥接网卡vethxxxx通信的. 这个虚拟桥接网卡没有ip地址

    每次启动一个容器, 宿主机都会生成一个vethxxxx网卡

    7: veth59d2aa0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
        link/ether 22:ab:9d:77:e8:c2 brd ff:ff:ff:ff:ff:ff link-netnsid 1
        inet6 fe80::20ab:9dff:fe77:e8c2/64 scope link 
           valid_lft forever preferred_lft forever
    9: vetha20334a@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
        link/ether 76:c1:7a:8c:aa:64 brd ff:ff:ff:ff:ff:ff link-netnsid 2
        inet6 fe80::74c1:7aff:fe8c:aa64/64 scope link 
           valid_lft forever preferred_lft forever
    root@ubuntu-1804-19:~# brctl show
    bridge name bridge id       STP enabled interfaces
    docker0     8000.0242d1156952   no      veth59d2aa0
                                            vetha20334a
    

    容器启动后, 每次生成的网卡都是新的 名字不一样 地址也可能变化, 而且启动多个容器, 会生成多个vethxxxx. 容器会使用172.17.0.0/16网段, 网关为0.1, 也就是docker0的地址, 之后的容器陆续用0.2,0.3. 一旦某个容器退出, 那么占用的ip会释放, 下一个启动的容器就会使用被释放的ip

    案例: 宿主机访问容器内部资源

    Ubuntu中 ps来自procps包, netstat来自net-tools包, 使用Ubuntu容器, 或者以Ubuntu为基础镜像做的应用容器时, 要先执行apt update, 然后再安装软件, 否则会提示无法找到软件

    nginx页面放在

    root@9ab8f94ef915:/# ls /usr/share/nginx/html
    50x.html  index.html
    root@9ab8f94ef915:/# echo nginx page in docker > /usr/share/nginx/html/index.html
    root@ubuntu-1804-19:~# curl 172.17.0.4
    nginx page in docker
    

    外界如何能访问到宿主机内的容器?

  • 将容器内开启的ip地址和端口号, 映射到宿主机eth0的ip和对应端口号, 利用DNAT技术, 把容器发布到外网
  • 通过将容器内的端口映射到宿主机对应的ip的端口上, 使得外界可以访问宿主机内的容器资源

    如果没有指定暴露端口, 那么启动容器后, 宿主机是不会监听的

    容器自身连外网用的SNAT, 作用在postrouting, DNAT作用在prerouting

    暴露容器端口, 实际利用的是DNAT技术, 会生成一个自定义链叫docker, 作用在NAT表的prerouting链上.

    用-P选项来映射容器服务端口, 需要本身容器就配置有端口启用 容器有几个端口就会映射几个端口到宿主机的ip上, 容器内的端口会映射到宿主机上的随机端口, 这样会暴露容器所有端口
    如果容器本身没有端口启用 也就不能映射
    
  • 映射端口前的iptables
  • root@ubuntu-1804-1:~# iptables -S -t nat  > pre_nat.rule
    root@ubuntu-1804-1:~# iptables -S   > pre_filter.rule
    root@ubuntu-1804-1:~# cat pre_nat.rule  # nat表
    -P PREROUTING ACCEPT
    -P INPUT ACCEPT
    -P OUTPUT ACCEPT
    -P POSTROUTING ACCEPT
    -N DOCKER
    -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
    -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
    -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
    -A DOCKER -i docker0 -j RETURN
    root@ubuntu-1804-1:~# cat pre_filter.rule   # filter表
    -P INPUT ACCEPT
    -P FORWARD DROP
    -P OUTPUT ACCEPT
    -N DOCKER
    -N DOCKER-ISOLATION-STAGE-1
    -N DOCKER-ISOLATION-STAGE-2
    -N DOCKER-USER
    -A FORWARD -j DOCKER-USER
    -A FORWARD -j DOCKER-ISOLATION-STAGE-1
    -A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    -A FORWARD -o docker0 -j DOCKER
    -A FORWARD -i docker0 ! -o docker0 -j ACCEPT
    -A FORWARD -i docker0 -o docker0 -j ACCEPT
    -A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
    -A DOCKER-ISOLATION-STAGE-1 -j RETURN
    -A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
    -A DOCKER-ISOLATION-STAGE-2 -j RETURN
    -A DOCKER-USER -j RETURN
    
    [root@ubuntu-1804-1:~]# docker run -d -P --name n1 nginx 
    #docker port 命令查看容器的端口映射情况, 这里显示容器内的tcp 80端口被映射到了宿主机的所有ip的32768上
    #暴露端口, 在宿主机监听, 并不需要宿主机的docker的service文件监听在tcp端口, -P暴露容器端口后, 宿主机默认就可以直接监听在0.0.0.0的随机端口上, 随机端口在启动容器时和宿主机绑定
    [root@ubuntu-1804-1:~]# docker port n1
    80/tcp -> 0.0.0.0:32768
    [root@ubuntu-1804-1:~]# ss -ntl
    State           Recv-Q            Send-Q                        Local Address:Port                        Peer Address:Port           
    LISTEN          0                 128                           127.0.0.53%lo:53                               0.0.0.0:*              
    LISTEN          0                 128                                 0.0.0.0:22                               0.0.0.0:*              
    LISTEN          0                 128                                    [::]:22                                  [::]:*              
    LISTEN          0                 128                                       *:32768                                  *:*   
    

    暴露端口后, 就可以在其他宿主机访问该宿主机的任意ip地址的32768端口, 进而访问到容器内的资源
    只有暴露了端口, 宿主机才会监听映射到宿主机的端口, 进而让外界访问到容器内部的资源

    [root@ubuntu-1804-2:~]# curl 10.0.0.239:32768
    <!DOCTYPE html>
    <title>Welcome to nginx!</title>
    <style>
        body {
            width: 35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
    </style>
    </head>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>
    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>
    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>
    
  • 映射端口后, 宿主机的nat和filter表
  • root@ubuntu-1804-1:~# iptables -S -t nat  > post_nat.rule
    root@ubuntu-1804-1:~# iptables -S   > post_filter.rule
    root@ubuntu-1804-1:~# cat post_nat.rule post_filter.rule 
    -P PREROUTING ACCEPT
    -P INPUT ACCEPT
    -P OUTPUT ACCEPT
    -P POSTROUTING ACCEPT
    -N DOCKER
    -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
    -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
    -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
    -A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 80 -j MASQUERADE
    -A DOCKER -i docker0 -j RETURN
    -A DOCKER ! -i docker0 -p tcp -m tcp --dport 32768 -j DNAT --to-destination 172.17.0.2:80
    -P INPUT ACCEPT
    -P FORWARD DROP
    -P OUTPUT ACCEPT
    -N DOCKER
    -N DOCKER-ISOLATION-STAGE-1
    -N DOCKER-ISOLATION-STAGE-2
    -N DOCKER-USER
    -A FORWARD -j DOCKER-USER
    -A FORWARD -j DOCKER-ISOLATION-STAGE-1
    -A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    -A FORWARD -o docker0 -j DOCKER
    -A FORWARD -i docker0 ! -o docker0 -j ACCEPT
    -A FORWARD -i docker0 -o docker0 -j ACCEPT
    -A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j ACCEPT
    -A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
    -A DOCKER-ISOLATION-STAGE-1 -j RETURN
    -A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
    -A DOCKER-ISOLATION-STAGE-2 -j RETURN
    -A DOCKER-USER -j RETURN
    
    root@ubuntu-1804-1:~# diff pre_nat.rule post_nat.rule 
    > -A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 80 -j MASQUERADE
    > -A DOCKER ! -i docker0 -p tcp -m tcp --dport 32768 -j DNAT --to-destination 172.17.0.2:80
    Docker自定义链, 访问目标端口32768, 通过DNAT转发到172.17.0.2:80
    
    root@ubuntu-1804-1:~# diff pre_filter.rule post_filter.rule 
    13a14
    > -A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j ACCEPT
    

    3.2 指定端口映射

    -p 约定宿主机ip和端口 并且选择性暴露容器中的端口 选择特定端口 大P是暴露所有容器的端口. -p更加精确, 但是需要确保宿主机本地端口没人占用

    dns udp 53 - dns discover 
    dns tcp 53 - dns master/slave
    

    注意: 多个容器映射到宿主机的端口不能冲突, 但容器内使用的端口可以相同

    方法1: 容器内的80端口映射到本地的随机端口
    docker run -p 80 --name n1 nginx
    方法2: 容器内的80端口映射到本地宿主机的81端口
           # 宿主机端口写在前面
    docker run -p 81:80 --name n2 nginx
    方法3:  容器内的80端口, 映射到宿主机指定ip指定端口
    docker run -p 10.0.0.239:82:80 --name n3 nginx
    方法4: 容器内的80端口, 映射到宿主机的指定ip和随机端口, 默认从32768开始
    docker run -p 10.0.0.239::80 --name n4 nginx
    方法5: 容器的80端口/指定协议, 映射到宿主机的指定ip和指定端口, 默认为tcp协议
    docker run -p 10.0.0.239:83:80/udp  --name n5 nginx  # 映射后, 宿主机也会监听对应的协议
    方法6: 一次性映射多个端口+协议
    docker run -p 8080:80/tcp -p 8443:443/tcp -p 53:53/udp --name n6 nginx
    

    修改已经创建好的容器的端口映射关系

    [root@ubuntu-1804-2:~]# docker run -d -p 81:80 --name n1 nginx
    e3fd55db570f57f9ccfc1c89912cb43a44d3cb478d7cc75539d4e803940fba70
    [root@ubuntu-1804-2:~]# docker port n1
    80/tcp -> 0.0.0.0:81
    
    此时容器n1的80端口映射到了宿主机的81端口, 如何修改为映射到8080端口?
    方法1: 临时修改防火墙DNAT转发策略
    Chain DOCKER (2 references)
     pkts bytes target     prot opt in     out     source               destination         
        0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0  
        0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:81 to:172.17.0.2:80
    ****************************************************
    修改Docker自定义链的DNAT转发策略
    [root@ubuntu-1804-2:~]# iptables -R  DOCKER 2 -t nat ! -i docker0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:80
    Chain DOCKER (2 references)
     pkts bytes target     prot opt in     out     source               destination         
        0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
        0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8080 to:172.17.0.2:80
    验证: 此时会发现, 虽然防火墙的转发策略修改了, 但是原本的81端口还是可以访问. 因为, 对于宿主机来说, 81端口始终还是被docker占用的
    [root@ubuntu-1804-2:~]# lsof -i :81
    COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
    docker-pr 1870 root    4u  IPv6  30831      0t0  TCP *:81 (LISTEN)
    root@ubuntu-1804-1:~# curl 10.0.0.229:8080
    <!DOCTYPE html>
    <title>Welcome to nginx!</title>
    <style>
        body {
            width: 35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
    </style>
    </head>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>
    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>
    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>
    -----------------
    root@ubuntu-1804-1:~# curl 10.0.0.229:81
    <!DOCTYPE html>
    <title>Welcome to nginx!</title>
    <style>
        body {
            width: 35em;
            margin: 0 auto;
            font-family: Tahoma, Verdana, Arial, sans-serif;
    </style>
    </head>
    <h1>Welcome to nginx!</h1>
    <p>If you see this page, the nginx web server is successfully installed and
    working. Further configuration is required.</p>
    <p>For online documentation and support please refer to
    <a href="http://nginx.org/">nginx.org</a>.<br/>
    Commercial support is available at
    <a href="http://nginx.com/">nginx.com</a>.</p>
    <p><em>Thank you for using nginx.</em></p>
    </body>
    </html>
    
    修改防火墙的问题:
    1. Docker的自定义链是容器启动的内置项, 因此, 一旦容器重启, 那么内置的防火墙规则还会生成
    [root@ubuntu-1804-2:~]# docker restart e3fd55db570f
    e3fd55db570f
    Chain DOCKER (2 references)
     pkts bytes target     prot opt in     out     source               destination         
        0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
        1    60 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8080 to:172.17.0.2:80
        0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:81 to:172.17.0.2:80
    2: 修改iptables都是临时的, 宿主机一旦重启, 就会失效
    
    方法2: 修改容器文件
    必须先停止docker服务, 否则直接修改json文件再重启docker是无效的
    systemctl stop docker
    容器信息会存放在/var/lib/docker/containers/目录下, 可以先通过docker insepct查看容器的id, 在和该目录下的目录名字作比对
    [root@ubuntu-1804-2:~]# docker ps
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
    e3fd55db570f        nginx               "/docker-entrypoint.…"   23 minutes ago      Up 8 minutes        0.0.0.0:81->80/tcp   n1
    [root@ubuntu-1804-2:~]# docker inspect e3fd55db570f
            "Id": "e3fd55db570f57f9ccfc1c89912cb43a44d3cb478d7cc75539d4e803940fba70",
    [root@ubuntu-1804-2:~]# ls /var/lib/docker/containers/
    e3fd55db570f57f9ccfc1c89912cb43a44d3cb478d7cc75539d4e803940fba70
    ****对比id找到对应的目录即可, 打开hostconfig.json文件******
    [root@ubuntu-1804-2:/var/lib/docker/containers/e3fd55db570f57f9ccfc1c89912cb43a44d3cb478d7cc75539d4e803940fba70]# vim hostconfig.json 
    {"Binds":null,"ContainerIDFile":"","LogConfig":{"Type":"json-file","Config":{}},"NetworkMode":"default","PortBindings":{"80/tcp":[{"HostIp":"","HostPort":"81"}]},"RestartPolicy":{"Name":"no","MaximumRetryCount":0},"AutoRemove":false,"VolumeDriver":"","VolumesFrom":null,"CapAdd":null,"CapDrop":null,"Capabilities":null,"Dns":[],"DnsOptions":[],"DnsSearch":[],"ExtraHosts":null,"GroupAdd":null,"IpcMode":"private","Cgroup":"","Links":null,"OomScoreAdj":0,"PidMode":"","Privileged":false,"PublishAllPorts":false,"ReadonlyRootfs":false,"SecurityOpt":null,"UTSMode":"","UsernsMode":"","ShmSize":67108864,"Runtime":"runc","ConsoleSize":[0,0],"Isolation":"","CpuShares":0,"Memory":0,"NanoCpus":0,"CgroupParent":"","BlkioWeight":0,"BlkioWeightDevice":[],"BlkioDeviceReadBps":null,"BlkioDeviceWriteBps":null,"BlkioDeviceReadIOps":null,"BlkioDeviceWriteIOps":null,"CpuPeriod":0,"CpuQuota":0,"CpuRealtimePeriod":0,"CpuRealtimeRuntime":0,"CpusetCpus":"","CpusetMems":"","Devices":[],"DeviceCgroupRules":null,"DeviceRequests":null,"KernelMemory":0,"KernelMemoryTCP":0,"MemoryReservation":0,"MemorySwap":0,"MemorySwappiness":null,"OomKillDisable":false,"PidsLimit":null,"Ulimits":null,"CpuCount":0,"CpuPercent":0,"IOMaximumIOps":0,"IOMaximumBandwidth":0,"MaskedPaths":["/proc/asound","/proc/acpi","/proc/kcore","/proc/keys","/proc/latency_stats","/proc/timer_list","/proc/timer_stats","/proc/sched_debug","/proc/scsi","/sys/firmware"],"ReadonlyPaths":["/proc/bus","/proc/fs","/proc/irq","/proc/sys","/proc/sysrq-trigger"]} 
    文件里的"HostPort":"81", 就是启动容器时映射到宿主机的端口, 需要修改为8080按照需求
    之后启动docker服务, 再启动对应的容器即可
    
    [root@ubuntu-1804-2:/var/lib/docker/containers/e3fd55db570f57f9ccfc1c89912cb43a44d3cb478d7cc75539d4e803940fba70]# systemctl start docker 
    [root@ubuntu-1804-2:/var/lib/docker/containers/e3fd55db570f57f9ccfc1c89912cb43a44d3cb478d7cc75539d4e803940fba70]# docker ps 
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    [root@ubuntu-1804-2:/var/lib/docker/containers/e3fd55db570f57f9ccfc1c89912cb43a44d3cb478d7cc75539d4e803940fba70]# docker ps -a
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                          PORTS               NAMES
    e3fd55db570f        nginx               "/docker-entrypoint.…"   31 minutes ago      Exited (0) About a minute ago                       n1
    [root@ubuntu-1804-2:/var/lib/docker/containers/e3fd55db570f57f9ccfc1c89912cb43a44d3cb478d7cc75539d4e803940fba70]# docker start e3fd55db570f
    e3fd55db570f
    [root@ubuntu-1804-2:/var/lib/docker/containers/e3fd55db570f57f9ccfc1c89912cb43a44d3cb478d7cc75539d4e803940fba70]# docker port n1
    80/tcp -> 0.0.0.0:8080
    [root@ubuntu-1804-2:/var/lib/docker/containers/e3fd55db570f57f9ccfc1c89912cb43a44d3cb478d7cc75539d4e803940fba70]# ss -ntl
    State                    Recv-Q                    Send-Q                                         Local Address:Port                                         Peer Address:Port                    
    LISTEN                   0                         128                                            127.0.0.53%lo:53                                                0.0.0.0:*                       
    LISTEN                   0                         128                                                  0.0.0.0:22                                                0.0.0.0:*                       
    LISTEN                   0                         128                                                        *:8080                                                    *:*                       
    LISTEN                   0                         128                                                     [::]:22                                                   [::]:*  
    
    Chain DOCKER (2 references)
     pkts bytes target     prot opt in     out     source               destination         
        0     0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
        0     0 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:8080 to:172.17.0.2:80
    
    方法2的问题: 这种情况需要停止宿主机上所有容器的服务, 导致宿主机所有容器都会停止. 具体用哪种方法, 就看生产需求
    

    3.3 查看容器日志

  • 容器通常不会持久使用 容器删除日志就没了. 因此容器中的日志通常以标准输出在终端显示 不会保存在文件里

  • 容器一般都是后台运行 没有终端输出的 怎么看日志呢?

  • docker logs命令 把日志输出到终端
    默认一次性输出 也可以-f 跟踪日志
    docker logs看的是容器的控制台输出 并不是真的是只有运行日志 
    
    [root@ubuntu-1804-2:~]# docker run -p 80:80 --name n1 nginx
    /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
    /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
    /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
    10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
    10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
    /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
    /docker-entrypoint.sh: Configuration complete; ready for start up
    10.0.0.239 - - [19/Jan/2021:15:27:18 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.58.0" "-"
    以前台启动容器时, 随着客户端的访问, 日志会直接输出到标准输出
    
    [root@ubuntu-1804-2:~]# docker logs -f df3e27fcc019
    /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
    /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
    /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
    10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
    10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
    /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
    /docker-entrypoint.sh: Configuration complete; ready for start up
    10.0.0.239 - - [19/Jan/2021:15:27:18 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.58.0" "-"
    10.0.0.239 - - [19/Jan/2021:15:30:13 +0000] "GET / HTTP/1.1" 200 612 "-" "curl/7.58.0" "-"
    

    3.4 传递运行命令

  • 运行容器时不运行容器启动默认运行指令. 如果容器本身有默认的运行命令, 比如nginx会运行nginx命令, 这时如果开启容器时传递了运行命令, 那么本身的默认命令就不会运行了
  • 可以用来临时查看容器信息
    [root@ubuntu-1804-2:~]# docker run --name n3 nginx cat /etc/issue
    Debian GNU/Linux 10 \n \l
    
  • 这种一般都是让那些没有内置的前台运行命令的容器能够持续运行, 而启动时传一个可以在前台运行的命令, 比如, tail -f
  • [root@ubuntu-1804-2:~]# docker run -d --name b1 busybox tail -f /etc/hosts
    5c99b45bf90c2c4b9a7089956a2e2802834b11fd9099c1eea1eebd32598236c9
    [root@ubuntu-1804-2:~]# docker ps
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
    5c99b45bf90c        busybox             "tail -f /etc/hosts"     5 seconds ago       Up 3 seconds                             b1
    

    3.5 查看容器内部的hosts文件

    [root@ubuntu-1804-2:~]# docker run  --name n5 nginx cat /etc/hosts
    127.0.0.1   localhost
    ::1 localhost ip6-localhost ip6-loopback
    fe00::0 ip6-localnet
    ff00::0 ip6-mcastprefix
    ff02::1 ip6-allnodes
    ff02::2 ip6-allrouters
    172.17.0.4  6bcdc5b187ed  # hosts文件中, 容器的ID和ip地址做了映射
    [root@ubuntu-1804-2:~]# docker ps -a
    CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS                NAMES
    6bcdc5b187ed        nginx               "/docker-entrypoint.…"   5 seconds ago       Exited (0) 4 seconds ago                        n5
    
    也可以手动修改hosts文件
    docker run -it --rm --add-host www.a.com:1.1.1.1 --add-host www.b.com:2.2.2.2 busybox
    

    3.6 指定容器的DNS

    默认情况下,  容器会使用宿主机的DNS信息
    [root@ubuntu-1804-2:~]# docker run --rm --name b2 busybox cat /etc/resolv.conf
    nameserver 223.5.5.5
    search Prac
    [root@ubuntu-1804-2:~]# systemd-resolve --status
             DNS Servers: 223.5.5.5
              DNS Domain: Prac
    
    指定容器使用的DNS三种方法
    1. 将DNS地址配置在宿主机, 但是这种方式还是统一的管理, 宿主机和容器还是使用相同的DNS
    2. 在容器启动时加选项 --dns=x.x.x.x
    3. 在/etc/docker/daemon.json 文件中指定, 让容器使用独立的DNS, 而宿主机的DNS保持不变
    
    单独指定, 每次启动容器都需要添加dns
    [root@ubuntu-1804-2:~]# docker run -it --rm --dns 1.1.1.1 --dns 2.2.2.2 --name b6 busybox cat /etc/resolv.conf
    search Prac
    nameserver 1.1.1.1
    nameserver 2.2.2.2
    
    通过修改配置文件, 让所有容器都使用特定的dns
    [root@ubuntu-1804-2:~]# vim /etc/docker/daemon.json 
      "registry-mirrors": ["https://odzb6i12.mirror.aliyuncs.com"],
      "dns" : ["114.114.114.114","119.29.29.29"]
    [root@ubuntu-1804-2:~]# systemctl restart docker
    [root@ubuntu-1804-2:~]# docker run --rm --name  b6 busybox  cat /etc/resolv.conf
    search Prac
    nameserver 114.114.114.114
    nameserver 119.29.29.29
    

    3.7 容器内和宿主机之间复制文件

    docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH | -
    docker cp [OPTIONS] SRC_PATH | - CONTAINER:DEST_PATH
    
    [root@ubuntu-1804-2:~]# docker run -d --name n1 nginx 
    # 从宿主机向容器复制文件
    [root@ubuntu-1804-2:~]# docker cp Sys_Init.sh n1:/etc
    [root@ubuntu-1804-2:~]# docker exec -it n1 bash
    root@f2ce10c746f1:/# ls /etc/
    Sys_Init.sh 
    # 从容器向宿主机复制文件
    [root@ubuntu-1804-2:~]# docker cp n1:/etc/issue ./
    [root@ubuntu-1804-2:~]# ls
    issue