zoukankan      html  css  js  c++  java
  • docker日常使用指南

    docker日常使用指南

    前言

    在对外提供应用程序时,常常碰到运行环境与开发环境不一致的情况,或虽然操作系统一样,但部署时可能碰到一些系统库版本不一样导致运行问题。或对外提供库时,没有客户需要的环境,需要花时间搭建虚拟机。这一些坑,大部分情况下都能通过docker这个工具帮我们方便的解决。因此学习docker是比较有价值的,同时,docker的使用也非常的简单,核心的命令比较少。本文对自己使用中用到的一些方式进行总结,一些理解可能不完全正确,更详细的可以去看官方文档。

    1.基础知识

    1.1 docker是什么

    docker是一种容器技术,是一种沙盒技术。它提供了一种非常遍历的打包机制,这种机制直接打包了应用运行所需要的整个操作系统,从而能够保证本地环境(开发环境)和生产环境(运行环境)的高度一致。
    想了解docker更底层技术的,可以去扩展阅读:Cgroups和Namespace技术
    扩展阅读2:daemon和client
    image

    1.2 与虚拟机(VM)的区别

    image
    图的左边,画出了虚拟机的工作原理。其中,名为 Hypervisor 的软件是虚拟机最主要的部分。它通过硬件虚拟化功能,模拟出了运行一个操作系统需要的各种硬件,比如 CPU、内存、I/O 设备等等。然后,它在这些虚拟的硬件上安装了一个新的操作系统,即 Guest OS。

    跟真实存在的虚拟机不同,在使用 Docker 的时候,并没有一个真正的“Docker 容器”运行在宿主机里面。Docker 项目帮助用户启动的,还是原来的应用进程,只不过在创建这些进程时,Docker 为它们加上了各种各样的 Namespace 参数。

    总而言之:Docker其实共享了宿主机操作系统的内核,因此内核不同的情况下,不能很好的使用docker, 比如windows上想用linux的docker就比较麻烦。Docker相对于VM比较轻量。

    1.3 镜像与容器

    镜像与容器的关系有点像类与对象的关系,镜像是一个静态概念,容器是一个运行时概念,容器是镜像的实例。通俗的讲,镜像就是放在硬盘上的,而容器是基于镜像跑起来后的东西。

    2.安装

    以下步骤默认宿主机为Ubuntu, 其它操作系统可以参考官方文档。
    快捷安装脚本可通过文末的方式去获得。

    2.1 在线安装

    安装docker: https://docs.docker.com/engine/install/ubuntu/

    sudo apt-get update
    sudo apt-get install 
        apt-transport-https 
        ca-certificates 
        curl 
        gnupg 
        lsb-release
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
    echo 
      "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu 
      $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    sudo apt-get update
    sudo apt-get install docker-ce docker-ce-cli containerd.io
    

    验证安装结果:

    sudo docker run --rm hello-world
    

    如果宿主机没有显卡或者我们不使用显卡,到这一步就结束了安装,如果要使用显卡,还需要进一步安装 nvidia-docker2:
    https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html#install-guide

    distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
    curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
    curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
    sudo apt-get update && sudo apt-get install -y nvidia-docker2
    sudo systemctl restart docker
    tee /etc/docker/daemon.json <<-'EOF'
    {
        "registry-mirrors": ["https://6kx4zyno.mirror.aliyuncs.com"],
        "exec-opts": ["native.cgroupdriver=systemd"],
        "default-runtime": "nvidia",
        "runtimes": {
            "nvidia": {
                "path": "/usr/bin/nvidia-container-runtime",
                "runtimeArgs": []
            }
        }
    }
    EOF
     
    sudo systemctl restart docker
    
    sudo docker run --rm --gpus all nvidia/cuda:11.0-base nvidia-smi 可用于验证能否访问GPU
    

    2.2 离线安装

    对于宿主机不让联网的时候,可以进行离线安装,也比较方便。
    可以参考这篇总结:https://fanfuhan.github.io/2019/11/22/docker_based_use/

    3.配置

    此节总结几个常见的可能修改的配置。大部分的配置都可以通过修改/etc/docker/daemon.json完成,也有例外。

    3.1 镜像存储位置设置

    docker镜像默认占用根目录空间,有些时候根目录空间不足,需要指定其他位置。
    此时通过修改/etc/docker/daemon.json完成:

    {
        "data_root":"myownpath", ### 存储位置
        "default-runtime": "nvidia",
        "runtimes": {
            "nvidia": {
                "path": "/usr/bin/nvidia-container-runtime",
                "runtimeArgs": []
            }
        }
    }
    

    执行命令使配置生效(修改daemon.json后都需要执行):

    systemctl daemon-reload
    systemctl restart docker
    

    3.2 设置镜像源

    镜像源是来获取镜像的地方,类似pip源,有时候官方源速度不行或根本访问不了。这时候可以通过设置代理(下节)或设置镜像源的方式去改善。

    {
        "data_root":"myownpath", ### 存储位置
         "registry-mirrors": ["https://6kx4zyno.mirror.aliyuncs.com"], ### 镜像源,可以设置多个
        "default-runtime": "nvidia",
        "runtimes": {
            "nvidia": {
                "path": "/usr/bin/nvidia-container-runtime",
                "runtimeArgs": []
            }
        }
    }
    

    3.3 代理设置

    有些时候需要挂代理去下载代码或者镜像。代理的设置分为对daemon的设置(主要影响镜像下载)和client(影响的是容器运行中的)。

    3.3.1 daemon代理

    docker是一个C/S架构,我们执行的docker命令实际是一种客户端,它会发起REST API到daemon(Server端),由daemon去拉取需要的镜像。此节设置的就是daemon的代理。几乎所有的daemon相关设置都可以在daemon.json中完成,但代理是个例外,这个设置需要创建:
    /etc/systemd/system/docker.service.d/http-proxy.conf 文件。

    [Service]
    Environment="HTTP_PROXY=http://proxy.example.com:80"
    Environment="HTTPS_PROXY=https://proxy.example.com:443"
    Environment="NO_PROXY=localhost,127.0.0.1,docker-registry.example.com,.corp"  ### 设置一些ip跳过代理
    

    3.3.2 容器代理

    创建~/.docker/config.json:

    {
     "proxies":
     {
       "default":
       {
         "httpProxy": "http://192.168.1.12:3128",
         "httpsProxy": "http://192.168.1.12:3128",
         "noProxy": "*.test.example.com,.example2.com,127.0.0.0/8"
       }
     }
    }
    

    还有一种方式是在Dockerfile或启动容器的时候设置环境变量:
    image

    4.docker的使用

    4.1 基础使用

    4.1.1 启动容器(docker run)

    docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
    

    docker run有比较多的参数可以设置,完整的参见:https://docs.docker.com/engine/reference/commandline/run/
    比较常用的是下面一些:

    -d: 后台运行容器,并返回容器ID;
    -i: 以交互模式运行容器,通常与 -t 同时使用;
    -P: 随机端口映射,容器内部端口随机映射到主机的端口
    -p: 指定端口映射,格式为:主机(宿主)端口:容器端口
    -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
    --name="nginx-lb": 为容器指定一个名称;
    --cpuset="0-2" or --cpuset="0,1,2": 绑定容器到指定CPU运行;
    -m :设置容器使用内存最大值;
    --net=bridge: 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;
    --expose=[]: 开放一个端口或一组端口;
    --volume , -v: 绑定一个卷
    --rm ,退出容器后删除名字 
    --restart ,重启选项,有no/always/on-failure/unless-stopped
    --entrypoint ,重写容器进程的入口
    

    比如我们执行sudo docker run -it --name test ubuntu:16.04就是以前台交互形式,以ubuntu:16.04镜像启动一个容器,第一次运行大概会输出下面这些内容:

    Unable to find image 'ubuntu:16.04' locally
    16.04: Pulling from library/ubuntu
    58690f9b18fc: Pull complete 
    b51569e7c507: Pull complete 
    da8ef40b9eca: Pull complete 
    fb15d46c38dc: Pull complete 
    Digest: sha256:454054f5bbd571b088db25b662099c6c7b3f0cb78536a2077d54adc48f00cd68
    Status: Downloaded newer image for ubuntu:16.04
    root@d8324be2d956:/# 
    

    也就是第一次运行时,会去拉取镜像,然后启动容器并进入容器终端(也可以通过docker pull 去自己拉取)。进入容器终端,我们就可以像普通终端一样去安装工具,编译代码等等了。
    而如果以后台形式运行,则是:

    sudo docker run -d --name test ubuntu:16.04
    a64fea9800522c5347eaa9feb87ee6c9d67762d81519cc58dbdeec5a8a786066
    

    容器将以后台形式运行。那么我们怎么进入在后台运行的容器呢?

    4.1.2 进入容器

    进入容器有2种方式,一种是attach, 一种是

    docker exec -it 容器ID/名称 bash
    

    推荐使用这种。进入后,可输入exit退出容器终端(只是退出终端,容器并不停止)

    4.1.3 停止/删除/启动/重启容器

    docker stop 容器ID/名称
    docker rm 容器ID/名称    ### 当容器发生重名时,我们就得删除以前的或者把新的改名
    docker start 容器ID/名称
    docker restart 容器ID/名称
    

    还是非常好理解的,基本上就是英文加容器即可。
    还有一个docker update可用于修改docker run时指定的参数。
    基本上学会以上操作,就能跑起来一个现场的容器,创建一个隔离的环境了。但仅仅有这些还不够,因为一旦删除容器了,我们在容器里创建的内容都不在了。

    4.2 进阶使用

    4.2.1 持久化(挂载主机硬盘)

    启动时通过-v 主机目录:容器目录选项即可将主机的目录挂载到容器中。

    sudo docker run -d --name test -v /home/xxx:/root/xxx ubuntu:16.04
    

    4.2.2 端口映射

    有时候容器内启动的是一个网络服务,这个服务去监听一个接口。但它监听的实际上是容器的内部端口,直接去访问是不行的,需要映射一个主机端口到容器的端口。
    通过-p 主机端口:容器端口或直接使用主机网络--net=host

    docker run -d -p 5000:5000 ubuntu:16.04 
    docker run -d --net=host ubuntu:16.04 
    

    4.2.3 自定义启动命令

    截止到目前,我们都没有指定过容器启动后运行什么命令,其实run的最后一个参数可以用于在启动容器后运行的命令:

    docker run -d --name test ubuntu:16.04  /bin/bash
    docker run -d --name test ubuntu:16.04  sh -c “/run.sh && /bin/bash” ### 多条命令拼接
    

    4.2.4 容器状态/日志查看

    > docker ps -a ###列出当前容器(包括已经停止的)
    CONTAINER ID   IMAGE                     COMMAND                  CREATED       STATUS       PORTS                                            NAMES
    b8862fc5d600   6e4bffa46d70              "kube-controller-man…"   13 days ago   Up 13 days                                                    k8s_kube-controller-manager_kube-controller-manager-alg-dev01_kube-system_5af433af822e5ae2fb8825ecf24ac394_11
    8ed05c4c9210   ebac1ae204a2              "kube-scheduler --au…"   13 days ago   Up 13 days                                                    k8s_kube-scheduler_kube-scheduler-alg-dev01_kube-system_8d0b3537ceaac4d2c6bbcb377f490c26_10
    f36f7818738b   66f781e54201              "nvidia-device-plugin"   2 weeks ago   Up 2 weeks                                                    k8s_nvidia-device-plugin-ctr_nvidia-device-plugin-daemonset-d2ct6_kube-system_09c990d8-83a5-4bc5-b8ad-c7bf00079f59_158850
    c60e540d83d6   k8s.gcr.io/pause:3.1      "/pause"                 2 weeks ago   Up 2 weeks                          
    
    > docker logs [-f等选项] 容器名/ID
    

    4.2.5 对容器修改的提交

    很多时候我们基于一个镜像启动了容器,在容器中我们安装了我们需要的软件,想在容器删除后也能够使用,而不是再装一次。这时就需要我们能够提交这个修改。和git类似,也是通过commit指令去提交。

    docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
    
    Create a new image from a container's changes
    
    Options:
      -a, --author string    Author (e.g., "John Hannibal Smith <hannibal@a-team.com>")
      -c, --change list      Apply Dockerfile instruction to the created image
      -m, --message string   Commit message
      -p, --pause            Pause container during commit (default true)
      
    

    例如在我们上述启动的ubuntu16.04的容器基础上,我们装了一些软件:

    docker commit test ubuntu:my16.04
    

    即可生成一个新的镜像(注意不是容器)。那么下次我们启动时直接用我们生成的这个镜像,启动的容器就包含了我们已经安装过的环境了。

    docker run -d --name test ubuntu:my16.04  /bin/bash
    

    4.3 制作镜像(Dockerfile)

    4.3.1 Dockerfile编写

    通过在容器内修改再提交的方式虽然能够生成镜像,但手动操作太多,而且不便于自动化。更常用的制作镜像的方式是Dockerfile。Dockerfile的基本使用比较简单,只需要掌握几个关键字:

    FROM ubuntu:16.04 ### FROM: 基础镜像
    ENV LANG C.UTF-8 
    ENV TZ=Asia/Shanghai ### 设置容器的时区, ENV用于设置环境变量
    
    RUN mkdir /opt/alg ### RUN: 执行一条命令,多个命令可以通过&&
    
    ADD config/ /opt/alg/config/ ### ADD: 除有COPY的功能外,还能通过URL下载文件,并且会自动解压缩
    COPY Dependency/ /opt/alg/Dependency/ ### COPY: 拷贝宿主机的文件或文件夹到镜像
    COPY bin/ /opt/alg/bin/
    COPY models/ /opt/alg/models/
    
    ENTRYPOINT ["/opt/alg/config/start_service.sh" ]  ### 设置容器启动的入口,类似于main函数,在docker run中可以通过 --entrypoint=XXX 覆盖,如果有这个,那么docker run时设置的command就会被当作它的参数
    
    

    除了用ENTRYPOINT去指定入口,还可以用CMD去指定,这2者也可能混用。它们之间的差异参考:https://blog.csdn.net/wuce_bai/article/details/88997725

    4.3.2 镜像生成

    有点类似于我们编译代码,docker提供的生成镜像的命令也是build:
    在Dockerfile所在目录执行:

    docker build . -t 镜像名:标签
    例如:
    docker build . -t myapp:v1
    

    镜像生成后,我们就可以使用前文的方式去启动容器了。

    4.4 镜像的保存、载入

    镜像既可以上传至官方的DockerHub供人pull,也可以自行搭建私有化的镜像仓库(如harbor)。但对于普通人或日常使用,更多的可能是想将镜像保存成一个可传输的文件,然后放到其他机器,再载入。这个docker也是有对应命令支持的。

    docker save [OPTIONS] IMAGE [IMAGE...]
    > docker save -o my_ubuntu_v3.tar runoob/ubuntu:v3 ###将镜像runoob/ubuntu:v3 保存成my_ubuntu_v3.tar
    docker load
    --input , -i : 指定导入的文件,代替 STDIN。
    --quiet , -q : 精简输出信息。
    > docker load -i my_ubuntu_v3.tar
    

    也可以结合其他压缩软件的命令,直接保存出压缩包:

    docker save <myimage>:<tag> | gzip > <myimage>_<tag>.tar.gz
    gunzip -c <myimage>_<tag>.tar.gz | docker load
    

    4.5 显卡的使用

    对于深度学习部署,很多可能需要显卡,使用docker时,需要保证显卡驱动安装,同时按上述步骤安装了nvidia-docker2。
    启动容器时,增加--gpus选项即可:

    sudo docker run --rm --gpus all nvidia/cuda:11.0-base nvidia-smi ### all: 所有显卡都可用
    sudo docker run --rm --gpus device=0,2 nvidia/cuda:11.0-base nvidia-smi ### 0,2 卡可用
    也可以用下列方式:
    sudo docker run --rm --gpus '"device=0"' nvidia/cuda:11.0-base nvidia-smi ### 0卡可用
    

    4.6 其他常用指令

    docker images 列出所有镜像
    docker rmi 删除镜像
    docker cp 宿主机和容器间拷贝文件
    

    还有一个不错的工具叫runlike,可以用来查看容器启动时的参数,可自行安装。

    5. 使用场景

    docker即可以用来发布应用,服务,这可能也是它的一种主要使用场景,也可以用来方便的创建不同的开发编译环境,比如在我们的ubuntu16.04机器上,去开发centos SDK, 甚至它也可以通过vnc去连接,获得图形化的开发环境。

    一键快捷安装脚本:

    链接:https://pan.baidu.com/s/1tb9tWEMzs6Ms1WDCzf1fqQ
    提取码:58q3
    若以上链接失效,关注 老司机的视觉屋,回复dockertool即可获取链接

    本文来自博客园,作者:haoliuhust,转载请注明原文链接:https://www.cnblogs.com/haoliuhust/p/15255577.html

  • 相关阅读:
    模块-- HASH
    模块 –SYS
    所谓情商高,就是要有分寸感
    20个很有用的CSS技巧
    CSS3中文手册基础知识
    赠书《JavaScript高级程序设计(第三版)》5本
    能走多远,取决于你与谁同行
    谷歌网站
    开发头条精选0724
    开发头条精选0723
  • 原文地址:https://www.cnblogs.com/haoliuhust/p/15255577.html
Copyright © 2011-2022 走看看