【Docker】一条龙文档

简介

Docker - 容器虚拟化技术,解决了运行环境和配置问题的软件容器。

一款产品从开发到上线,从操作系统,到运行环境,再到应用配置。作为开发+运维之间的协作,我们需要关心很多东西,这也是很多互联网公司都不得不面对的问题,特别是各种版本的迭代之后,不同版本环境的兼容,对运维人员都是考验。

环境配置如此麻烦,换一台机器,就要重来一次,费力费时。很多人想到,能不能从根本上解决问题,软件可以带环境安装?也就是说,安装的时候,把原始环境一模一样地复制过来。开发人员利用 Docker 可以消除协作编码时“在我的机器上可正常工作”的问题。


Docker的基本组成

仓库

仓库(Repository)是集中存放镜像文件的场所。

  • 横向对比:
    • Maven仓库,存放各种jar包的地方;
    • github仓库,存放各种项目源码的地方;
    • Docker公司提供的官方registry被称为Docker Hub,存放各种镜像模板的地方。

仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
最大的公开仓库是链接: Docker Hub,存放了数量庞大的镜像供用户下载。
国内的公开仓库包括阿里云、网易云等

镜像

UnionFS(联合文件系统)
Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。

Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录。类似千层饼哈哈哈哈哈。下面展示 mysql:8.0.30镜像联合文件系统。

[root@localhost ~] docker inspect mysql:8.0.30 
[
    {
        "Id": "sha256:43fcfca0776df8e192d1647da2866237fbd9f8e875fb496e4ca887369b2dd995",
        "RepoTags": [
            "mysql:8.0.30"
        ],
        # 千层饼展示
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:05dc728e5e49b5db657ec403b875f757afdd8d31f624eea76d706d6eee6395b2",
                "sha256:e413712982712f9b6795a558563749f8b9413af078f02290a8b132df58d93587",
                "sha256:3efed8ece3f742cea267c6097b6ef1f5beb34d431da0404797b817bcd228e15b",
                "sha256:5bd7288fc71b94c6b6a0fe48881a23c18924c59b419328b1e0516c289406c56d",
                "sha256:089c3ce0a7bd0ec7d0146ee50cf1f6a0762a2bf37c6d52a1b391e1058fe6325a",
                "sha256:548aa849c503d8ec7bb942c9cfb217499c1c68b5c974aa6daa6d6e9ab0ccef85",
                "sha256:390f3d47b221eb0b0d435bd5deca0d228a2becc69e8b638755205bdde6ce9d8f",
                "sha256:ae26f7a91c57484862161f9d36ea6a09c94252a32a7163ac9b8dfa7d3e1bda45",
                "sha256:6a6f178837b4195dba9daf066f5bec032a75a2597a341972c961a4bb2ede9055",
                "sha256:80411d0a9f6fb5bea4177979c8d04ff1b6a7a22d24cba2465cb2e61cc6916a64",
                "sha256:1ee6afb508377ecb9d9a003fff84b132d023b0bd7b779092fdd5a1785a0b513b"
            ]
        }
    }
]

最大的一个好处就是 ——共享资源

  • 有多个镜像都从相同的 base 镜像构建而来,那么宿主机只需在磁盘上保存一份base镜像,同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
  • ps:镜像都是只读
容器
  • 从面向对象角度
    Docker 利用容器(Container)独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。就像是Java中的类和实例对象一样,镜像是静态的定义,容器是镜像运行时的实体。容器为镜像提供了一个标准的和隔离的运行环境,它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台

  • 从镜像容器角度
    可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。

常用命令

常用命令列表,基础命令略过演示。

DOCKEER
systemctl status docker查看服务状态
systemctl start docker启动服务
docker version查看版本
docker system df 查看镜像/容器/数据卷所占的空间
镜像命令
docker images列出本地主机上的镜像
docker image ls -f dangling=true查看所有的虚悬镜像
docker search xxx查找xxx镜像
docker pull xxx拉取xxx镜像
docker rmi 镜像id删除镜像
docker rmi -f 镜像id强制删除镜像
docker rmi -f ${docker images -qa}删除全部镜像
docker image prune删词所有的虚悬镜像 -- docker rmi -f
容器命令
docker ps-a 查看正在运行+历史运行的容器
-l查看最近创建的容器(正在+ 历史运行)
-n 2查看最近2个创建的容器(正在+ 历史运行)
-q查看所有正在运行的容器 id
--no-trunc不截断输出
docker start 容器ID/容器名启动某容器
docker restart容器ID/容器名重启某容器
docker stop容器ID/容器名停止容器
docker kill容器ID/容器名强制停止容器
docker rm 容器ID删除容器
docker rm -f 容器ID强制删除某容器
docker top 容器ID查看容器内运行的进程,进程号、端口号等
docker inspect 容器ID查看容器内部细节
docker cp 容器ID:内路径 目的路径容器宿主机间拷贝
docker commit -m="描述" -a="作者" 容器ID 目标镜像名:[标签名]从容器生成一个镜像
docker run -d后台运行容器,并返回容器ID,也即启动守护式容器
-i以交互模式运行容器,通常与 -t 同时使用
-P随机端口映射
-p指定端口映射
--name为容器指定一个名称
docker save保存镜像为tar包
网络命令
docker network ls查看网络列表
docker network create xxx创建网络
docker network inspect xxx查看网络源数据
docker network rm xxx删除网络
docker inspect 容器名 | tail -n 20查看容器网络

容器数据卷

Docker将程序与运行的环境打包形成容器运行,运行可以伴随着容器,但是我们对数据的要求希望是持久化的,容器之间希望有可能共享数据。

Docker容器产生的数据,如果不通过docker commit生成新的镜像,使得数据做为镜像的一部分保存下来,那么当容器删除后,数据自然也就没有了。

卷就是目录或文件,存在于一个或多个容器中,由Docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性。

卷的设计目的就是数据的持久化,完全独立于容器的生存周期。

数据卷特点
  1. 数据卷可在容器之间共享或重用数据
  2. 卷中的更改可以直接生效
  3. 数据卷中的更改不会包含在镜像的更新中
  4. 数据卷的生命周期一直持续到没有容器使用它为止
容器数据卷

docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像

创建本地文件并挂载到容器中:

[root@localhost nginx]# echo 'test-nginx' > a.txt
[root@localhost nginx]# ls
a.txt

[root@localhost nginx]# docker run -p 19000:80  -v /root/dist/nginx:/etc/nginx/dist  -d  --name nginx-test nginx
38c20a18f8b5b2e52786957e92381ad7b290c531f878ee605872cac531f3aad0

[root@localhost nginx]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
38c20a18f8b5        nginx               "/docker-entrypoint.…"   3 seconds ago       Up 1 second         0.0.0.0:19000->80/tcp               nginx-test

[root@localhost nginx]# docker exec -it nginx-test bash
root@38c20a18f8b5:/# cd etc/nginx/dist/
root@38c20a18f8b5:/etc/nginx/dist# cat a.txt 
test-nginx

查看该容器信息,Mounts展示数据卷绑定信息:宿主机 /root/dist/nginx 挂载到容器内部 /etc/nginx/dist
在这里插入图片描述
在容器中改变a.txt中的值,宿主机的值也同步改变。提供多种模式挂载,一般配置文件建议只读模式:or

卷的集成和共享

docker run -it --privileged=true --volumes-from 父 --name xx 镜像

DockerFile

Dockerfile是用来构建Docker镜像的构建文件,是由一系列命令和参数构成的脚本。

以熟悉的某nginx tag为例:
在这里插入图片描述

  1. 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
  2. 指令按照从上到下,顺序执行
  3. #表示注释
  4. 每条指令都会创建一个新的镜像层,并对镜像进行提交
执行流程
  1. docker从基础镜像运行一个容器
  2. 执行一条指令并对容器作出修改
  3. 执行类似docker commit的操作提交一个新的镜像层
  4. docker再基于刚提交的镜像运行一个新容器
  5. 执行dockerfile中的下一条指令直到所有指令都执行完成
小总结

从应用软件的角度来看,Dockerfile、Docker镜像与Docker容器分别代表软件的三个不同阶段:

  • Dockerfile是软件的原材料
  • Docker镜像是软件的交付品
  • Docker容器则可以认为是软件的运行态

Dockerfile面向开发,Docker镜像成为交付标准,Docker容器则涉及部署与运维,三者缺一不可,合力充当Docker体系的基石。

  • Dockerfile,需要定义一个Dockerfile,Dockerfile定义了进程需要的一切东西。Dockerfile涉及的内容包括执行代码或者是文件、环境变量、依赖包、运行时环境、动态链接库、操作系统的发行版、服务进程和内核进程(当应用进程需要和系统服务和内核进程打交道,这时需要考虑如何设计namespace的权限控制)等等;
  • Docker镜像,在用Dockerfile定义一个文件之后,docker build时会产生一个Docker镜像,当运行 Docker镜像时会真正开始提供服务;
  • Docker容器,容器是直接提供服务的。
保留字指令
指令注解
FROMFROM 基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是FROM
MAINTAINER维护者的姓名和邮箱地址
RUN容器构建时需要运行的命令,RUN是在 docker build时运行。用 shell的命令即可
EXPOSE当前容器对外暴露出的端口
WORKDIR指定在创建容器后,终端默认登陆的目录,一个落脚点
USER指定该镜像以什么样的用户去执行,如果都不指定,默认是root
ENV用来在构建镜像过程中设置环境变量
ADD将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
COPY类似ADD,拷贝文件和目录到镜像中。将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置,目标路径不用事先建好,路径不存在的话,会自动创建
VOLUME容器数据卷,用于数据保存和持久化工作
CMDCMD 指定容器启动后的要干的事情,CMD是在 docker run时运行,命令和 RUN 一样。Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
ENTRYPOINT也是用来指定一个容器启动时要运行的命令,类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序

PS: 当指定了ENTRYPOINT后,CMD的含义就发生了改变,不再是直接的运行命令,而是将CMD的内容作为参数传给ENTRYPOINT指令,换句话说,将变为:

<ENTRYPOINT>   "<CMD>"

Docker 网络

Docker是如何内部访问的?
启动docker后,产生一个 docker0 的虚拟网桥。并自动创建三个网络模式(container模式不做介绍)
docker0
网络模式
网络模式对比:

模式说明
bridge为每一个容器分配、设置 IP 等,并将容器连接到docker0虚拟网桥,默认为该模式。
host容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP 和端口。
none容器有独立的 Network namespace,但并没有对其进行任何网络设置。
bridge

Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。

每启动一个docker容器,Docker就会给容器分配一个ip,就会有一个网卡docker0桥接模式, 使用的技术是evth-pair技术。
网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配。

  • 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
  • 每个容器实例内部也有一块网卡,每个接口叫eth0;
  • docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。
    evth-pair
    此时在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。
    在这里插入图片描述
host

直接使用宿主机的 IP 地址与外界进行通信,容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个。将不会虚拟出自己的网卡而是使用宿主机的IP和端口。
在这里插入图片描述

docker run -d --network host

在这里插入图片描述
此时通过宿主机ip直接访问
在这里插入图片描述

none

在none模式下,并不为Docker容器进行任何网络配置。

docker run -d --network none

自定义网络

很方便,自身就维护好了主机名和ip的对应关系
如果容器之间有依赖关系,可以使用自定义网络,因为容器可能因重启等原因,其容器ip发生变化,使用自定义网络,可以直接指定域名,不需担心这种问题。

docker network create [OPTIONS] NETWORK
具体可以查看help

创建相关网络 (bridge)
在这里插入图片描述
创建相关容器接入自己创建的网络
在这里插入图片描述
进入nginx01 ping nginx02
在这里插入图片描述
在用户定义网络模式下,开发者可以使用任何docker支持的第三方网络driver来定制容器的网络。并且,docker 1.9 以上的版本默认自带了bridge和overlay两种类型的自定义网络driver。可以用于集成calico、weave、openvswitch等第三方厂商的网络实现。 除了docker自带的bridge driver,其他的几种driver都可以实现容器的跨主机通信。而基于bdrige driver的网络,docker会自动为其创建iptables规则,保证与其他网络之间、与docker0之间的网络隔离。

Docker-compose 容器编排

Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。只要一个命令,就能同时启动/关闭这些容器。

简单来说,要运行一个web项目,除了启动web服务容器之外,还需要启动它依赖的mysql、redis等等,这时候手动一个个启动非常麻烦,可使用docker-compose。

使用步骤:

  1. Dockerfile先行,定义好相关镜像。
  2. 编写docker-compose.yml文件,定义一个完整业务单元,安排好整体应用中的各个容器服务。
  3. 执行docker-compose up,启动并运行整个应用程序,完成一键部署上线。
compose 命令

常用指令

命令注解
docker-compose up -d启动所有docker-compose服务并后台运行
docker-compose down停止并删除容器、网络;但不会删除卷和镜像
docker-compose ps展示当前docker-compose编排过的运行的所有容器
docker-compose top展示当前docker-compose编排过的容器进程
docker-compose config -q检查配置,有问题才有输出
docker-compose logs xxx查看容器输出的日志
docker-compose xx /bin/bash进入容器实例内部
docker-compose restart重启服务
docker-compose start启动服务
docker-compose stop停止服务
docker-compose -h查看帮助
docker-compose pause/unpause暂停/恢复服务容器
compose 文件组成
  • version
    docker compose的版本号,与docker的版本有对应关系:
    官方文档

  • image
    指定运行容器的镜像名称或id,如果本地镜像不存在,将会尝试拉取这个镜像。

  • ports
    容器与宿主机的端口映射信息,格式为宿主机端口:容器端口,可以不指定宿主机端口,此时宿主机将会随机选择端口。

    PS:端口建议双引号

    version: "3.2"  
    
    services:
      mytomcat: 
        image: nginx
        ports:
          - "16284:80"
    
  • volumes
    数据卷映射

    • 宿主机绝对路径:容器绝对路径
    • 数据卷名称:容器绝对路径,这种方式必须在后面声明所使用的数据卷。
    version: "3.2"  
    
    services:
      mytomcat: 
        image: nginx
        ports:
          - "16284:80"
        volumes:
          - nginx:/etc/nginx/dist  # 数据卷映射,必须在下面定义数据卷名称
    
    volumes:
      nginx:  # 声明使用的数据卷,没有会自动创建,卷名为 文件夹名_自定义数据卷名 的格式
    
  • networks
    配置容器使用哪个网络(桥)

    version: "3.2"  
    
    services:
      mytomcat: 
        image: nginx
        ports:
          - "16284:80"
        networks: 
          - mynet  # 指定网络,须在下面定义
    
    networks:
      mynet:  # 定义网络。定义后才能在上面使用,否则报错
    

    启动容器后,compose会自动帮我们创建 mynet 网络

    • 如果我们在模板文件中没有指定容器用的网络,那么compose会自动创建一个名称为项目名_default的网络,项目名为yml模板文件所在的目录名。
    • 如果我们在模板文件中指定了容器的网络,那么compose会自动创建一个名称为项目名_自定义网络名的网络。

    也可以使用创建好的网络:

    version: "3.2"  
    
    services:
      mytomcat: 
        image: nginx  
        ports:
          - "16284:8080"
        networks: 
          - mynet  # 指定容器网络
    
    networks:
      mynet:  # 定义网络
        external: true  # 该网络须存在,不存在必须先手动创建,否则报错
    
  • container_name
    指定容器的名称。不指定时默认由compose生成带项目名称前缀的容器名

    version: "3.2"  
    
    services:
      mytomcat: 
        container_name: nginx01 # 指定容器的名称
        image: nginx
        ports:
          - "16284:80"
    
  • environment
    设置环境变量,可以使用数组或字典两种格式。
    如果只给定变量名称,不指定值,会自动获取宿主机上对应的环境变量的值,防止数据泄露。

    环境变量的名称或值中用到true|false或者yes|no这样的布尔表达式,建议放到引号里,避免解析错误

    version: "3.2"  
    
    services:
      mysql5: 
        container_name: mysql01  
        image: mysql:5.7
        ports:
          - "13306:3306"
        environment:
          - MYSQL_ROOT_PASSWORD: root  # 等价写法MYSQL_ROOT_PASSWORD=root
    
  • env_file
    从文件中获取环境变量,可以为单独的文件路径或列表

    一般我们会把一些敏感信息环境变量放到文件中,比如mysql密码。这样compose模板文件中不会暴露密码

    如果通过docker-compose -f file方式来指定yml模板文件,则env_file中变量的路径会基于模板文件路径

    如果有变量名称与 environment 指令冲突,则以后者为准

    # 指定单个环境变量文件
    env_file: .env
    
    # 指定多个环境变量文件
    env_file: 
      - ./common.env
      - /opt/secrets.env
    

    环境变量文件中每一行必须符合格式,支持#开头的注释行

    # mysql密码
    MYSQL_ROOT_PASSWORD=root
    
  • command
    用于run镜像之后,覆盖容器启动时的默认命令,比如启动redis时:docker run -p 6379:6379 -d --name redis01 -v redis.data:/data -v redis.conf:/etc/redis/redis.conf redis:5 redis-server /etc/redis/redis.conf,需要如下配置。

    version: "3.2"  
    
    services:
      redis5: 
        container_name: redis01  
        image: redis:5
        ports:
          - "16379:6379"
        volumes:
          - redis.data:/data
          - redis.conf:/etc/redis
        command: "redis-server /etc/redis/redis.conf"  # 容器启动时要运行的命令
    
  • depends_on
    解决容器之间的依赖、启动先后问题。

    version: "3.2"  
    
    services:
      web:
        image: webapp:latest
        ports:
          - "8080:8080"
        depends_on:  # 依赖于redis5和mysql5.7,会先启动redis5和mysql5.7
          - redis5   # 注意一定要写services下面配置的服务id,而不是容器名称
          - mysql5.7
        
      redis5: 
        container_name: redis01
        image: redis:5
        ports:
          - "6379:6379"
        volumes:
          - redis.data:/data
          - /dockermapping/redis/conf/redis.conf:/etc/redis/redis.conf
        command: "redis-server /etc/redis/redis.conf"  # 指定容器启动时要运行的命令
      
      mysql5.7: 
        container_name: mysql01
        image: mysql:5.7
        ports:
          - "3306:3306"
        environment:
          - MYSQL_ROOT_PASSWORD: root
    
  • build
    如果要将我们自己的应用放到compose模板文件中进行编排,首先要用dockerfile生成镜像,然后在compose模板中编排,这样做稍显麻烦。

    build指令可以一步到位,在compose模板中将指定的dockerfile打包成镜像后再运行。

    version: "3.2"  
    
    services:
      web:
        build:
          context: myweb  # 指定上下文目录,即dockerfile所在目录
          dockerfile: Dockerfile  # 指定dockerfile的文件名
        ports:
          - "8080:8080"
        depends_on:  # 先启动redis5和mysql5.7
          - redis5   # 要配置的服务id,而不是容器名称
          - mysql5.7
        
      redis5: 
        container_name: redis01
        image: redis:5
        ports:
          - "6379:6379"
        volumes:
          - redis.data:/data
          - redis.conf:/etc/redis
        command: "redis-server /etc/redis/redis.conf"  # 指定容器启动时要运行的命令
      
      mysql5.7: 
        container_name: mysql01
        image: mysql:5.7
        ports:
          - "3306:3306"
        environment:
          - MYSQL_ROOT_PASSWORD: root
    
  • 限制容器可用内存

    version: "3.2"
    services:
      redis:
        image: redis:alpine
        container_name: redis01
        deploy:
          resources:
            limits:
              memory: 2G  # 限制容器可用最大内存为2G
    
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

总在寒冷清秋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值