首页 > 技术文章 > -linux-Docker从入门到秃顶

arher 2020-12-11 19:42 原文

Docker 是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余项目。它基于 Google 公司推出的 Go 语言实现。 项目后来加入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在 GitHub 上 进行维护。Docker 自开源后受到广泛的关注和讨论,以至于 dotCloud 公司后来都改名为 Docker Inc。Redhat 已经在其 RHEL6.5 中集中支持 Docker;Google 也在其 PaaS 产品中广泛应用。Docker 项目的目标是实现 轻量级的操作系统虚拟化解决方案。 Docker 的基础是 Linux 容器(LXC)等技术。在 LXC 的基础上 Docker 进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便。用户操作 Docker 的容器就像操 作一个快速轻量级的虚拟机一样简单。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植 的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不 会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。

一 为什么要使用Docker

1 Docker容器虚拟化的好处

在云时代,开发者创建的应用必须要能很方便地在网络上传播,也就是说应用必须脱离底层物理硬件的限制;同时必须满足“任何时间任何地点”可获取可使用的特点。因此,开发者们需要一种新型的创建分布式应用程序 的方式,快速分发部署,而这正是 Docker 所能够提供的最大优势。Docker 提供了一种更为聪明的方式,通过 容器来打包应用、解耦应用和运行平台。这意味着迁移的时候,只需要在新的服务器上启动需要的容器就可以了, 无论新旧服务器是否是同一类别的平台。这无疑帮助我们节约了大量的宝贵时间,并降低部署过程出现问题的风险。

2 Docker在开发和运维中的优势

对于开发和运维人员来说,最梦寐以求的效果可能就是一次创建和配置,之后可以在任意地方、任意时间让 应用正常运行,而 Docker 恰恰可以实现这一中级目标。具体来说,在开发和运维过程中,Docker 具有以下几 个方面的优势:

  • 更快的交付和部署:使用 Docker,开发人员可以使用镜像来快速构建一套标准的开发环境;开发完之 后,测试和运维人员可以直接使用完全相同的环境来部署代码。只要是开发测试过的代码,就可以确保 在生产环境无缝运行。Docker 可以快速创建和删除容器,实现快速迭代,节约开发、测试及部署的时间。
  • 更高效的利用资源:运行 Docker 容器不需要额外的虚拟化管理程序的支持,Docker 是内核级的虚拟化,可以实现更高的性能,同时对资源的额外需求很低,与传统的虚拟机方式相比,Docker 的性能要提高 1 ~ 2 个数量级。
  • 更轻松的迁移和扩展:Docker 容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑等等,同时支持主流的操作系统发行版本。这种兼容性能让用户可以在不同的平台之间轻松的迁移应用。
  • 更轻松的管理和更新:使用 Dockerfile,只需要小小的配置修改,就可以替代以往大量的更新工作。所有的修改都以增量的方式被分发和更新,从而实现自动化并且高效的容器管理。

3 Docker与虚拟机的比较

作为一种轻量级的虚拟化方式,Docker 在运行应用上跟传统的虚拟机的方式相比具有如下显著优势:

  • Docker 容器启动很快,启动和停止可以实现秒级,相比传统的虚拟机方式(分钟级)要快速很多。
  • Docker 容器对系统资源需求很少,一台主机上可以同时运行数千个 Docker 容器。
  • Docker 通过类似 git 设计理念的操作来方便用户获取、分发和更新应用镜像,存储复用,增量更新。
  • Docker 通过 Dockerfile 支持灵活的自动化创建和部署机制,可以提高工作效率,并标准化流程。
特性 容器 虚拟机
启动速度 秒级 分钟级
性能 接近原生 较好
内存 MB级 GB级
硬盘适应 MB级 GB级
运行密度 单台主机支持上千个 单台主机支持几个
隔离性 安全隔离 完全隔离
迁移 优秀 一般

二 Docker与虚拟化

Docker 以及其他容器技术,都属于操作系统虚拟化范畴,操作系统细腻化最大的特点就是不需要额外的 supervisor 支持。Docker 虚拟化方式之所以有众多优势,跟操作系统虚拟化技术自身的设计和实现分不开。

传统方式是在硬件层面实现虚拟化,需要有额外的虚拟机管理应用和虚拟机操作系统层。Docker 容器时在 操作系统层面实现虚拟化,直接复用本地主机的操作系统,因此更加轻量级。

三 Docker概念和使用

Docker 中有三个核心概念:镜像、容器和仓库。因此,准确把握这三大概念对于掌握 Docker 技术尤为重要。

  1. 镜像(Image)

Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完

整的一套 Ubuntu16.04 最小系统的 root 文件系统。

  1. 容器(Container)

镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。

  1. 仓库(Repository)

用来保存镜像的仓库。当我们构建好自己的镜像之后,需要存放在仓库中,当我们需要启动一个镜像时, 可 以在仓库中下载下来。

1 使用Docker镜像

​ docker 镜像是 docker 中三大概念之一,其主要作用是作为启动容器的模板。

1)获取镜像

镜像是运行容器的模板,官方 Docker Hub 仓库已经提供了许多镜像共开发者使用。如果我们需要获取某 个镜像则可以去 docker 仓库下载所需的镜像。

下载镜像的格式:docker pull image_name:image_version

下载镜像实例:

[root@arther-linux ~]# docker pull nginx:1.17
Trying to pull repository docker.io/library/nginx ... 
1.17: Pulling from docker.io/library/nginx
afb6ec6fdc1c: Pull complete 
b90c53a0b692: Pull complete 
11fa52a0fdc0: Pull complete 
Digest: sha256:6fff55753e3b34e36e24e37039ee9eae1fe38a6420d8ae16ef37c92d1eb26699
Status: Downloaded newer image for docker.io/nginx:1.17

下载的时候,我们可以看到有若干层组成,像 afb6ec6fdc1c 这样的字符串是层的唯一 ID(实际上,完整的 ID 包括 256 比特, 64 个十六进制字符组成)。使用 docker pull 命令下载中会获取并输出镜像的各层信息。当不 同的镜像包括相同的层的时候,本地仅存一份内容,减小存储空间。

2)查看镜像信息

​ 镜像主要包括镜像文件、镜像tag以及镜像详细信息等等。

镜像列表

使用两条命令

​ docker images 或 docker image ls

可以列举本地主机上已有镜像的基本信息

[root@arther-linux ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/redis     latest              74d107221092        13 days ago         104 MB
myredis             latest              74d107221092        13 days ago         104 MB
docker.io/nginx     1.19.2              7e4d58f0e5f3        2 months ago        133 MB
docker.io/nginx     1.17                9beeba249f3e        6 months ago        127 MB

列举信息,可以看到几个字段信息:

  • 镜像来源:来自哪个仓库,默认来自:hub.docker.com
  • 镜像标签:比如1.17、latest
  • 镜像ID:例如9beeba249f3e
  • 镜像创建时间:例如 6 months ago
  • 镜像大小:127 MB

镜像大小信息只是表示了该镜像的逻辑体积大小,实际上由于相同的镜像层本地只会存储一份,物理上占用

的存储空间会小于各镜像逻辑体积之和。

image子命令主要支持如下选项:

  • -a:列出所有(包括临时文件)镜像文件
[root@arther-linux ~]# docker images -a
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/redis     latest              74d107221092        13 days ago         104 MB
myredis             latest              74d107221092        13 days ago         104 MB
docker.io/nginx     1.19.2              7e4d58f0e5f3        2 months ago        133 MB
docker.io/nginx     1.17                9beeba249f3e        6 months ago        127 MB

  • --digests=true|false:列出镜像的数字摘要值
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/redis     latest              74d107221092        13 days ago         104 MB
myredis             latest              74d107221092        13 days ago         104 MB
docker.io/nginx     1.19.2              7e4d58f0e5f3        2 months ago        133 MB
docker.io/nginx     1.17                9beeba249f3e        6 months ago        127 MB
[root@arther-linux ~]# docker images --digests
REPOSITORY          TAG                 DIGEST                                                                    IMAGE ID            CREATED             SIZE
docker.io/redis     latest              <none>                                                                    74d107221092        13 days ago         104 MB
myredis             latest              <none>                                                                    74d107221092        13 days ago         104 MB
docker.io/nginx     1.19.2              sha256:c628b67d21744fce822d22fdcc0389f6bd763daac23a6b77147d0712ea7102d0   7e4d58f0e5f3        2 months ago        133 MB
docker.io/nginx     1.17                sha256:6fff55753e3b34e36e24e37039ee9eae1fe38a6420d8ae16ef37c92d1eb26699   9beeba249f3e        6 months ago        127 MB
  • -q:仅显示ID信息
[root@arther-linux ~]# docker images -q
74d107221092
74d107221092
7e4d58f0e5f3
9beeba249f3e
为镜像添加tag

为了方便后续工作使用特定的镜像,还可以使用docker tag命令来为本地的镜像添加标签。

[root@arther-linux ~]# docker tag redis:latest myredis:latest
[root@arther-linux ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/redis     latest              74d107221092        13 days ago         104 MB
myredis             latest              74d107221092        13 days ago         104 MB
docker.io/nginx     1.19.2              7e4d58f0e5f3        2 months ago        133 MB
docker.io/nginx     1.17                9beeba249f3e        6 months ago        127 MB
使用inspect命令来查看详细信息

使用docker inspect 命令来获取镜像的详细信息,包括PID、作者、架构等等。

[root@arther-linux ~]# docker inspect redis
[
    {
        "Id": "sha256:74d107221092875724ddb06821416295773bee553bbaf8d888ababe9be7b947f",
        "RepoTags": [
            "docker.io/redis:latest",
            "myredis:latest"
        ],
        "RepoDigests": [],
        "Parent": "",
        "Comment": "",
        "Created": "2020-11-18T08:28:42.383873008Z",
        "Container": "1a904a9885d0bdcb73bbb4899df9632a1f89a75c6bee47c55981e4834124c3cf",
        "ContainerConfig": {
            "Hostname": "1a904a9885d0",
            "Domainname": "",
            "User": "",
            "AttachStdin": false,
            "AttachStdout": false,
            "AttachStderr": false,
            "ExposedPorts": {
                "6379/tcp": {}
            },
					...
使用history命令来查看镜像历史
[root@arther-linux ~]# docker history redis
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
74d107221092        13 days ago         /bin/sh -c #(nop)  CMD ["redis-server"]         0 B                 
<missing>           13 days ago         /bin/sh -c #(nop)  EXPOSE 6379                  0 B                 
<missing>           13 days ago         /bin/sh -c #(nop)  ENTRYPOINT ["docker-ent...   0 B                 
<missing>           13 days ago         /bin/sh -c #(nop) COPY file:df205a0ef6e6df...   374 B               
<missing>           13 days ago         /bin/sh -c #(nop) WORKDIR /data                 0 B                 
<missing>           13 days ago         /bin/sh -c #(nop)  VOLUME [/data]               0 B                 
<missing>           13 days ago         /bin/sh -c mkdir /data && chown redis:redi...   0 B                 
<missing>           13 days ago         /bin/sh -c set -eux;   savedAptMark="$(apt...   30.5 MB             
<missing>           13 days ago         /bin/sh -c #(nop)  ENV REDIS_DOWNLOAD_SHA=...   0 B                 
<missing>           13 days ago         /bin/sh -c #(nop)  ENV REDIS_DOWNLOAD_URL=...   0 B                 
<missing>           13 days ago         /bin/sh -c #(nop)  ENV REDIS_VERSION=6.0.9      0 B                 
<missing>           13 days ago         /bin/sh -c set -eux;  savedAptMark="$(apt-...   4.15 MB             
<missing>           13 days ago         /bin/sh -c #(nop)  ENV GOSU_VERSION=1.12        0 B                 
<missing>           13 days ago         /bin/sh -c groupadd -r -g 999 redis && use...   329 kB              
<missing>           13 days ago         /bin/sh -c #(nop)  CMD ["bash"]                 0 B                 
<missing>           13 days ago         /bin/sh -c #(nop) ADD file:d2abb0e4e7ac177...   69.2 MB      

注意:有些构建信息过长,可以使用--no-trunc 选项来输出完整信息。

搜索镜像

在docker中搜索镜像主要使用Search子命令,默认只搜索Docker Hub官方镜像仓库中的镜像。其语法为

docker search [option] keyword

支持的命令选项主要包括:

  • -f:过滤输出内容
# 搜索官方提供的带有Redis关键字的镜像
[root@arther-linux ~]# docker search -f is-official=true redis
INDEX       NAME              DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
docker.io   docker.io/redis   Redis is an open source key-value store th...   8792  

[OK] 

# 搜索被收藏超过 8000 个的并且关键词包括 Redis 的镜像
[root@arther-linux ~]# docker search -f stars=8000 redis
INDEX       NAME              DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
docker.io   docker.io/redis   Redis is an open source key-value store th...   8792      [OK]    
  • --limit:限制输出结果
[root@arther-linux ~]# docker search -f stars=8 --limit 3 redis
INDEX       NAME                                       DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
docker.io   docker.io/redis                            Redis is an open source key-value store th...   8792      [OK]       
docker.io   docker.io/bitnami/redis                    Bitnami Redis Docker Image                      168                  [OK]
docker.io   docker.io/rediscommander/redis-commander   Alpine image for redis-commander - Redis m...   47                   
  • --no-trunc:不截断输出结果
[root@arther-linux ~]# docker search -f stars=8 --no-trunc redis
INDEX       NAME                                       DESCRIPTION                                                                            STARS     OFFICIAL   AUTOMATED
docker.io   docker.io/redis                            Redis is an open source key-value store that functions as a data structure server.     8792      [OK]       
docker.io   docker.io/bitnami/redis                    Bitnami Redis Docker Image                                                             168                  [OK]
docker.io   docker.io/sameersbn/redis                                                                                                         82                   [OK]
docker.io   docker.io/grokzen/redis-cluster            Redis cluster 3.0, 3.2, 4.0, 5.0, 6.0                                                  72                   
docker.io   docker.io/rediscommander/redis-commander   Alpine image for redis-commander - Redis management tool.                              47                   [OK]
docker.io   docker.io/kubeguide/redis-master           redis-master with "Hello World!"                                                       33                   
docker.io   docker.io/redislabs/redisearch             Redis With the RedisSearch module pre-loaded. See http://redisearch.io                 29                   
docker.io   docker.io/redislabs/redis                  Clustered in-memory database engine compatible with open source Redis by Redis Labs    27                   
docker.io   docker.io/arm32v7/redis                    Redis is an open source key-value store that functions as a data structure server.     22                   
docker.io   docker.io/oliver006/redis_exporter          Prometheus Exporter for Redis Metrics. Supports Redis 2.x, 3.x, 4.x and 5.x
输出参数释义
  • NAME:尽享仓库源的名称
  • DESCRIPTION:镜像的描述
  • OFFICIAL:是否docker官方发布
  • stars:类似 Github 里面的 star,表示点赞、喜欢的意思。
  • AUTOMATED: 自动构建。

3) 删除和清理镜像

在 docker 中,删除镜像主要使用 rmi 子命令,清理镜像主要使用 prune 子命令。

使用标签删除镜像
[root@arther-linux ~]# docker rmi myredis
Untagged: myredis:latest
[root@arther-linux ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/redis     latest              74d107221092        13 days ago         104 MB
docker.io/nginx     1.19.2              7e4d58f0e5f3        2 months ago        133 MB
docker.io/nginx     1.17                9beeba249f3e        6 months ago        127 MB

如果根据IMAGE ID 删除镜像,那么redis也会被删除,因为myredis与redis引用的是同一个IMAGE ID,只是打上的标签不同,myredis是我们自定义的标签。

参数:

​ -f: 强制删除镜像

[root@arther-linux ~]# docker rmi -f redis
Untagged: redis:latest
Deleted: sha256:74d107221092875724ddb06821416295773bee553bbaf8d888ababe9be7b947f
Deleted: sha256:d951b383737320b4e1ac7f9bb63f3919bcf25363ccb59fbb52a41e45ba70ffdd
Deleted: sha256:d3b2581a1c92973ee9a41fc00e5628047ce7e644a66240fb859b38831bd525b4
Deleted: sha256:a447231da503a58432b4d7409980139206fdf398fbde189d8a7229dd0663f472
Deleted: sha256:f786204ca260bcaef3d47ecad10821878028239072c65ceb2a1f212f275f9367
Deleted: sha256:b68afce5f52461f79be59806be00e43ea95152a0358b8dc5de9ac3f486a70d7e
Deleted: sha256:f5600c6330da7bb112776ba067a32a9c20842d6ecc8ee3289f1a713b644092f8
清理镜像

使用一段时间之后,docker 会产生很多临时文件,以及一些没有被使用的镜像,我们可以通过 docker image prune 命令来进行清理。

参数:

​ -a: 删除所有无用的镜像不光是临时镜像

[root@arther-linux ~]# docker image prune -a
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N] y
Deleted Images:
untagged: docker.io/nginx:1.17
untagged: docker.io/nginx@sha256:6fff55753e3b34e36e24e37039ee9eae1fe38a6420d8ae16ef37c92d1eb26699
deleted: sha256:9beeba249f3ee158d3e495a6ac25c5667ae2de8a43ac2a8bfd2bf687a58c06c9
deleted: sha256:8fb6373b4cca3383756d7fd7843dd92f95827e5f2913609e09a9621dcddb3752
deleted: sha256:8b09841626797a03a9fe5e73aa38aeacf9ff0ce85a3004236ff35234eec3b35c
deleted: sha256:ffc9b21953f4cd7956cdf532a5db04ff0a2daa7475ad796f1bad58cfbaf77a07
untagged: docker.io/redis:latest
untagged: docker.io/redis@sha256:5b98e32b58cdbf9f6b6f77072c4915d5ebec43912114031f37fa5fa25b032489
deleted: sha256:74d107221092875724ddb06821416295773bee553bbaf8d888ababe9be7b947f
deleted: sha256:d951b383737320b4e1ac7f9bb63f3919bcf25363ccb59fbb52a41e45ba70ffdd
deleted: sha256:d3b2581a1c92973ee9a41fc00e5628047ce7e644a66240fb859b38831bd525b4
deleted: sha256:a447231da503a58432b4d7409980139206fdf398fbde189d8a7229dd0663f472
deleted: sha256:f786204ca260bcaef3d47ecad10821878028239072c65ceb2a1f212f275f9367
deleted: sha256:b68afce5f52461f79be59806be00e43ea95152a0358b8dc5de9ac3f486a70d7e
deleted: sha256:f5600c6330da7bb112776ba067a32a9c20842d6ecc8ee3289f1a713b644092f8

Total reclaimed space: 231 MB
  
[root@arther-linux ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
docker.io/nginx     1.19.2              7e4d58f0e5f3        2 months ago        133 MB

​ -f : 强制删除镜像,而不进行提示。

[root@arther-linux ~]# docker image prune -a -f
Deleted Images:
untagged: docker.io/redis:latest
untagged: docker.io/redis@sha256:5b98e32b58cdbf9f6b6f77072c4915d5ebec43912114031f37fa5fa25b032489
deleted: sha256:74d107221092875724ddb06821416295773bee553bbaf8d888ababe9be7b947f
deleted: sha256:d951b383737320b4e1ac7f9bb63f3919bcf25363ccb59fbb52a41e45ba70ffdd
deleted: sha256:d3b2581a1c92973ee9a41fc00e5628047ce7e644a66240fb859b38831bd525b4
deleted: sha256:a447231da503a58432b4d7409980139206fdf398fbde189d8a7229dd0663f472
deleted: sha256:f786204ca260bcaef3d47ecad10821878028239072c65ceb2a1f212f275f9367
deleted: sha256:b68afce5f52461f79be59806be00e43ea95152a0358b8dc5de9ac3f486a70d7e
deleted: sha256:f5600c6330da7bb112776ba067a32a9c20842d6ecc8ee3289f1a713b644092f8

4)构建镜像

​ 构建镜像一般有三种情况,基于容器导入、基于本地模板导入、基于Dockerfile创建。

基于容器保存

主要格式:docker container_id commit

主要参数:

  • -a 作者信息
  • -m 提交信息
  • -p 提交时,暂停容器运行

启动一个容器、修改并保存

# 启动容器 -d:后台启动     
[root@arther-linux ~]# docker run -d -it centos /bin/bash
Unable to find image 'centos:latest' locally
Trying to pull repository docker.io/library/centos ... 
latest: Pulling from docker.io/library/centos
3c72a8ed6814: Pull complete 
Digest: sha256:76d24f3ba3317fa945743bb3746fbaf3a0b752f10b10376960de01da70685fbd
Status: Downloaded newer image for docker.io/centos:latest
50177d1cafb40134f64faa9c20e1bd6097bcbc8f23a9a869f1c6ee8568376721

# 将django目录下的文件挂载到容器html文件下
# 没有权限,需要再加参数,有权限操作html文件
[root@arther-linux django]# docker run -d -v /test/django/:/usr/share/nginx/html --privileged=true -P nginx:1.19.5 
3ead75a41602d0366316688891997d5f77b478d050971d2eb58befc11590c92c

# 查看运行的容器
root@arther-linux ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
50177d1cafb4        centos              "/bin/bash"         13 minutes ago      Up 13 minutes                           relaxed_visvesvaraya

# 进入到该容器中
[root@arther-linux ~]# docker exec  relaxed_visvesvaraya touch test

# 在此容器中添加镜像文件
[root@arther-linux ~]# docker commit -m "Add a file" -a "Alvin" relaxed_visvesvaraya
sha256:c4cb6a13ea8003039d2745d90e72a3515fb4f72e5deeda800e3afc418a875160
  
# 再次查看镜像,多了一个镜像文件
[root@arther-linux ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
<none>              <none>              c4cb6a13ea80        36 seconds ago      215 MB
docker.io/nginx     1.19.2              7e4d58f0e5f3        2 months ago        133 MB
docker.io/centos    latest              0d120b6ccaa8        3 months ago        215 MB

5)保存镜像

有时我们需要将一台电脑上的镜像复制到另一台电脑上使用,除了可以借助仓库外,还可以直接将镜像保存成一个文件,再拷贝到另一台电脑上导入使用。

对于镜像的导出和导入,Docker提供了两种方案。

使用export和import 导出和导入

export 和 import 的针对点是容器,将本机的容器导出为镜像包。(所以只能操作一个镜像)

使用export保存容器为镜像

# 保存该容器为镜像并重定向覆盖到nginx.tar,相当于复制一份,没有对原容器进行剪切
[root@arther-linux ~]# docker export relaxed_visvesvaraya>nginx.tar

# 在当前操作的目录下保存
[root@arther-linux ~]# ll
总用量 217180
-rw-------. 1 root root      3108 11月 19 16:42 anaconda-ks.cfg
-rw-r--r--. 1 root root 222377984 12月  1 18:56 nginx.tar
-rw-------. 1 root root      2392 11月 19 16:42 original-ks.cfg
 
# 将该容器导出为主机的镜像文件,并没有影响该容器的运行,所以只是相当于复制操作。
[root@arther-linux test]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
50177d1cafb4        centos              "/bin/bash"         38 minutes ago      Up 38 minutes                           relaxed_visvesvaraya

使用import导入包为镜像

# 将主机的镜像文件导入为docker中的镜像
[root@arther-linux test]# docker import nginx.tar nginx:v1
sha256:134f27a95ff8860656bca73313e0fb7a70c39b9465adbd366d63b5a81207666e
[root@arther-linux test]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               v1                  134f27a95ff8        25 seconds ago      215 MB
<none>              <none>              c4cb6a13ea80        21 minutes ago      215 MB
docker.io/nginx     1.19.2              7e4d58f0e5f3        2 months ago        133 MB
docker.io/centos    latest              0d120b6ccaa8        3 months ago        215 MB

使用save和load 导出和导入

save 和 load 的针对的点是镜像,将本机的镜像导入、导出为镜像包。(所以可以操作多个镜像)

使用save保存镜像

# 将docker中的镜像文件导出重定向到主机的test目录下
[root@arther-linux test]# docker save docker.io/nginx >busybox.tar
[root@arther-linux test]# ll
总用量 350808
-rw-rw-r--. 1 bibibi user10         0 11月 25 20:28 1.txt
-rw-r--r--. 1 root   user10 136842752 12月  1 19:51 busybox.tar

使用save保存多个镜像

[root@arther-linux test]# docker save -o test.tar docker.io/nginx:1.19.2 docker.io/centos:latest 
[root@arther-linux test]# ll
总用量 701596
-rw-rw-r--. 1 bibibi user10         0 11月 25 20:28 1.txt
-rw-------. 1 root   user10 359206400 12月  1 19:58 test.tar
  
# 导入验证是否有两个镜像
[root@arther-linux test]# docker load <test.tar
Loaded image: docker.io/centos:latest
Loaded image: docker.io/nginx:1.19.2
    
# 由于已存在该镜像,所以不会重复
[root@arther-linux ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               v1                  134f27a95ff8        About an hour ago   215 MB
<none>              <none>              c4cb6a13ea80        About an hour ago   215 MB
docker.io/nginx     1.19.2              7e4d58f0e5f3        2 months ago        133 MB
docker.io/centos    latest              0d120b6ccaa8        3 months ago        215 MB

使用load导入镜像

[root@arther-linux test]# docker load <test.tar
Loaded image: docker.io/centos:latest
Loaded image: docker.io/nginx:1.19.2
两种方案的差别
  • 文件大小不同

    • export 导出的镜像文件体积小于 save 保存的镜像,因为export仅保存镜像且只保存一个镜像,save相对保存的信息较为完整且能保存多个镜像。
  • 是否可以对镜像重命名

    • docker import 可以为镜像指定新名称,docker load 不能对载入的镜像重命名。
  • 是否可以同时将多个镜像打包到一个文件中

    • docker export 不支持,docker save 支持。
  • 是否包含镜像历史

    • export 导出(import 导入)是根据容器拿到的镜像,再导入时会丢失镜像所有的历史记录和元数据信息(即仅保存容器当时的快照状态),所以无法进行回滚操作。

      save 保存(load 加载)的镜像,没有丢失镜像的历史,可以回滚到之前的层(layer)。

  • 应用场景不同

    • docker export 的应用场景:主要用来制作基础镜像,比如我们从一个 ubuntu 镜像启动一个容器,然后安装一些软件和进行一些设置后,使用 docker export 保存为一个基础镜像。然后,把这个镜像分发给其他人使用,比如作为基础的开发环境。
    • docker save 的应用场景:如果我们的应用是使用 docker-compose.yml 编排的多个镜像组合,但我们要部署的客户服务器并不能连外网。这时就可以使用 docker save 将用到的镜像打个包,然后拷贝到客户服务器上使用 docker load 载入。

3 使用Docker容器

1)创建容器

在Docker中,真正对外提供服务的还是容器。

创建容器的格式:docker run [option] image [cmd]

# 80是容器默认的端口,映射到主机的自定义端口
[root@arther-linux ~]# docker run -d --name nginx -p 8080:80 nginx
Unable to find image 'nginx:latest' locally
Trying to pull repository docker.io/library/nginx ... 
latest: Pulling from docker.io/library/nginx
852e50cd189d: Pull complete 
571d7e852307: Pull complete 
addb10abd9cb: Pull complete 
d20aa7ccdb77: Pull complete 
8b03f1e11359: Pull complete 
Digest: sha256:6b1daa9462046581ac15be20277a7c75476283f969cb3a61c8725ec38d3b01c3
Status: Downloaded newer image for docker.io/nginx:latest
dac679815977e6132bad3d6471c158241cb3c16769e1140f84bbc229078f8e49

# 此时可以通过浏览器进行访问
http://10.211.55.3:8080/

容器启动参数

启动参数 意义
-d 以守护进程方式运行
-p 指定映射端口
-P 随机映射端口
-i 保持标准输入打开
-t 分配一个伪终端
-v 设置挂载文件到主机上
--privileged 挂载文件的权限,为True则是有该权限
--rm 当容器关闭时自动删除
--name 为启动的容器设置一个名字
--network 指定使用哪个网络
-e 设置容器中的环境变量
--link 连接到另一个容器
-h 指定容器内的主机名

2)停止容器

docker 终止容器是首先向容器发送 SIGTERM 信号,等待一段时间超时后(默认 10 秒),再发送 SIGKILL 信号 来终止容器。

[root@arther-linux ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
dac679815977        nginx               "/docker-entrypoin..."   5 minutes ago       Up About a minute   0.0.0.0:8080->80/tcp   nginx
[root@arther-linux ~]# docker stop nginx
nginx

[root@arther-linux ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

# 没有运行的容器了

# 该容器停止运行,不能访问
# 再重启时,不需要docker run 的命令

[root@arther-linux ~]# docker start nginx 
nginx
[root@arther-linux ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
dac679815977        nginx               "/docker-entrypoin..."   11 minutes ago      Up 30 seconds       0.0.0.0:8080->80/tcp   nginx

3)进入容器

在使用容器的过程中,我们难免需要进入容器进行排查问题。

attach

attach 是最早 docker 官方推出的进入容器的命令了,不过使用该命令有一个问题。当多个窗口同时使用该命令 进入该容器时,所有的窗口都会同步显示。如果有一个窗口阻塞了,那么其他窗口也无法再进行操作,当所有窗 口退出时,容器结束。

exec

既 attach 之后,exec 是官方推出的有一个新的进入容器的命令,这个命令相当于在容器中执行一个命令。

[root@arther-linux ~]# docker exec -it nginx /bin/bash
root@dac679815977:/# 
nsenter

需要配合 docker inspect 来使用(早期没有 exec 命令时,企业当中最长用的方式之一),Docker 是用 golang 语言开发,所以它也支持 go 语言的摸版语法。

[root@instance-gvpb80ao docs]# nsenter --target $( docker inspect -f {{.State.Pid}} nginxv1 ) --mount --uts --ipc --net --pid 
mesg: ttyname failed:: No such device 
root@6f99ae8757f7:/#
ssh

在生产环境中排除了使用 docker attach 命令进入容器之后,相信大家第一个想到的就是 ssh。在镜像(或容器) 中安装 SSH Server,这样就能保证多人进入容器且相互之间不受干扰了,相信大家在当前的生产环境中(没有 使用 Docker 的情况)也是这样做的。但是使用了 Docker 容器之后不建议使用 ssh 进入到 Docker 容器内。

总结

进入 docker container 中一般情况下有 4 种方式,最常用的是 exec 和 nsenter 这两种。

Nsenter 和 exec 之间的区别:

  • Exec 是 docker 自带的命令,Nsenter 是 Linux 提供的命令。
  • Exec 相当于在容器内执行一个命令,而 Nsenter 是仅仅进入容器之中而已。

4)删除容器

可以使用 docker rm 命令来删除处于终止或退出状态的容器,命令格式为:docker rm container。

[root@arther-linux ~]# docker rm nginx

强制删除一个正在运行的容器

[root@arther-linux ~]# docker rm -f nginx

5)导入与导出容器

​ 某些时候,需要将容器从一个系统迁移到另外一个系统,此时可以使用DOcker的导入和导出功能,这也是Docker自身提供的一个重要特性。

导出容器

导出容器是指,导出一个已经创建的容器到一个文件,不管此时这个容器是否处于运行状态 可以使用 docker

[container] export 令,该命令格式为:

[root@arther-linux ~]# docker export relaxed_visvesvaraya>nginx.tar
导入容器

导出的文件又可以使用 docker [ container] import 命令导人变成镜像,该命令格式为:

[root@arther-linux test]# docker import nginx.tar nginx:v1
sha256:134f27a95ff8860656bca73313e0fb7a70c39b9465adbd366d63b5a81207666e
  
# 然后可以通过run命令启动成为容器

实际上,既可以使用 docker load 命令来导入镜像存储文件到本地镜像库,也可以使 docker [container] import 命令来导入一个容器快照到本地镜像库 这两者的区别在于 容器快照文件将丢弃所有的历史记录和元数据信息 (即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积更大 此外,从容器快照文件导人时可以重新指定标签等元数据信息。

主要用来制作基础镜像,比如我们从一个 ubuntu 镜像启动一个容器,然后安装一些软件和进行一些设置后,使用 docker export 保存为一个基础镜像。然后,把这个镜像分发给其他人使用,比如作为基础的开发环境。

查看容器

查看容器详情可以使用 docker container inspect [OPTIONS] CONTAINER [CONTAINER . .. ]子命令。

[root@arther-linux ~]# docker inspect nginx
[
    {
        "Id": "dac679815977e6132bad3d6471c158241cb3c16769e1140f84bbc229078f8e49",
        "Created": "2020-12-01T12:21:49.144136711Z",
        "Path": "/docker-entrypoint.sh",
        "Args": [
            "nginx",
            "-g",
            "daemon off;"
        ],
        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 18242,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2020-12-01T12:45:55.304273001Z",
            "FinishedAt": "2020-12-01T12:45:47.984137475Z"
        },
				......

5)容器命令详解

复制命令

复制命令类似于 Linux 系统中的 scp 命令,是将宿主主机上的内容上传到容器中,也可能是将容器中的文件 下载到宿主主机中。

# 将容器中的内容复制到宿主的主机中
[root@arther-linux ~]# docker cp 746be4d00a18:/root/test.txt /

# 将宿主文件复制到容器中
[root@arther-linux /]# docker cp a.tar.gz 520b5630ef9c:/root
   

示意图

四 Docker网络

Docker 本身的技术依赖于 Linux 内核虚拟化技术的发展。所以 Docker 对 Linux 内核的特性有很强的依赖。

1 网络基础

其中Docker使用到的与Linux网络有关的技术分别有:网络名称空间、Veth、Iptables、网桥、路由。

1)网络名称空间

​ 为了支持网络协议栈的多个实例,Linux 在网络协议栈中引入了网络名称空间(Network Namespace),这些独立的协议栈被隔离到不同的命名空间中。处于不同的命名空间的网络协议栈是完全隔离的,彼此之间无法进行网络通信,就好像两个“平行宇宙”。通过这种对网络资源的隔离,就能在一个宿主机上虚拟多个不同的网络环境,而 Docker 正是利用这种网络名称空间的特性,实现了不同容器之间的网络隔离。在 Linux 的网络命名空间内可以有自己独立的 Iptables 来转发、NAT 及 IP 包过滤等功能。

​ Linux 的网络协议栈是十分复杂的,为了支持独立的协议栈,相关的这些全局变量都必须修改为协议栈私有。最好的办法就是让这些全局变量成为一个 Net Namespace 变量的成员,然后为了协议栈的函数调用加入一个Namespace 参数。这就是 Linux 网络名称空间的核心。所以的网络设备都只能属于一个网络名称空间。当然,通常的物理网络设备只能关联到 root 这个命名空间中。虚拟网络设备则可以被创建并关联到一个给定的命名空间中,而且可以在这些名称空间之间移动。

创建一个命名空间
[root@arther-linux /]# ip netns add test01
[root@arther-linux /]# ip netns add test02
[root@arther-linux /]# ip netns list
test02
test01
Veth设备

引入 Veth 设备对是为了在不同的网络名称空间之间进行通信,利用它可以直接将两个网络名称空间链接起 来。由于要连接的两个网络命名空间,所以 Veth 设备是成对出现的,很像一对以太网卡,并且中间有一根直连 的网线。既然是一对网卡,那么我们将其中一端称为另一端的 peer。在 Veth 设备的一端发送数据时,它会将数据直接发送到另一端,并触发另一端的接收操作。

但是如果需要建立多个设备之间的关联,如10个设备每个都需要互相关联,那么就是从9开始递归加到1,这样的操作及其麻烦。所以需要类似中转站样的设备,能够与所有设备进行关联,然后通过它进行转发数据。

网桥

​ Linux 可以支持多个不同的网络,它们之间能够相互通信,就需要一个网桥。网桥是二层的虚拟网络设备,它是把若干个网络接口“连接”起来,从而报文能够互相转发。网桥能够解析收发的报文,读取目标MAC地址的信息,和自己记录的MAC表结合,来决定报文的转发目标网口。

​ 网桥设备 brO 绑定了 eth0、 eth1 。对于网络协议械的上层来说,只看得到 brO 。因为桥接是在数据链 路层实现的 ,上层不需要关心桥接的细节,于是协议枝上层需要发送的报文被送到 brO ,网桥设备的处理代码判断报文该被转发到 ethO 还是 ethl ,或者两者皆转发。反过来,从 ethO 或从 ethl 接收到的报文被提交给网桥的处理代码,在这里会判断报文应该被转发、丢弃还是提交到协议枝上层。 而有时 ethl 也可能会作为报文的源地址或目的地址 直接参与报文的发送与接收,从而绕过网桥。

Iptables

​ 我们知道, Linux 络协议樵非常高效,同时比较复杂 如果我们希望在数据的处理过程中对关心的数据进行一些操作该怎么做呢? Linux 提供了一套机制来为用户实现自定义的数据包处理过程。

​ 在 Linux 网络协议棋中有一组回调函数挂接点,通过这些挂接点挂接的钩子函数可以在 Linux 网络棋处理数据包的过程中对数据包进行 些操作,例如过滤、修改、丢弃等 整个挂接点技术叫作 Netfilter lptables

​ Netfilter 负责在内核中执行各种挂接的规则,运行在内核模式中:而 lptables 是在用户模式下运行的进程,负责协助维护内核中 Netfilter 的各种规则表 通过 者的配合来实现整个 Linux 网络协议战中灵活的数据包处理机制。

总结

设备 作用总结
network namespace 主要提供了关于网络资源的隔离,包括网络设备、IPv4和 IPv6 协议栈、IP 路由表、防火墙、/proc/net 目录、/sys/class/net 目录、端口(socket)等。
linux Bridge 功能相当于物理交换机,为连在其上的设备(容器)转发数据帧。如 docker0 网桥。ip
iptables 主要为容器提供NAT以及容器网络安全
veth pair 两个虚拟网卡组成的数据通道。在 Docker 中,用于连接 Docker 容器和 Linux ,Bridge一端在容器中作为 eth0 网卡,另一端在 Linux Bridge 中作为网桥的一个端口。

2)Docker 网络模式

​ Docker使用Linux桥接的方式,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为 Container-IP,同时 Docker 网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的 Container-IP 直接通信。

​ Docker 网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法通过直接 Container-IP 访问到容器。如果容器希望外部访问能够访问到,可以通过映射容器端口到宿主主机(端口映射),即 docker run 创建容器时候通过 -p 或 -P 参数来启用,访问容器的时候就通过[宿主机 IP]:[容器端口]访问容器。

Docker 网络模型 配置 说明
host模式 --network=host 容器和宿主机共享 Network namespace。
containe模式 --network=container:ID 容器和另外一个容器共享 Network namespace。 kubernetes 中的 pod 就是多个容器共享一个 Network namespace。
none模式 --network=none 容器有独立的 Network namespace,但并没有对其进行任何网络设置,如分配 veth pair 和网桥连接,配置 IP 等。
bridge模式 --network=bridge 当 Docker 进程启动时,会在主机上创建一个名为 docker0 的虚拟网桥,此主机上启动的 Docker 容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。(默认为该模式)
Host模式

​ 如果启动容器的时候使用 host 模式,那么这个容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口。但是,容器其他方面,如文件系统、进程列表等还是和宿主机隔离的。

​ 使用 host 模式的容器可以直接使用宿主机的 IP 地址与外界通信,容器内部的服务端口也可以使用宿主机的 端口,不需要进行 NAT,host 最大的优势就是网络性能比较好,但是 docker host 上已经使用的端口就不能再 用了,网络的隔离性不好。

​ 实现原理:docker容器命名空间网络连接根命名空间的网络。所以通过Host模式生成的多个容器的网络名称空间是不同的。

​ 127.0.0.1 通过根命名空间内的lo互通。

[root@arther-linux /]# docker run -d --name my_web --network host nginx
3196582b47ef7c75739e129ae0b77e75621e83a760b6f949bad716fcc7e7581e
[root@arther-linux /]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
3196582b47ef        nginx               "/docker-entrypoin..."   14 seconds ago      Up 13 seconds                                my_web

[root@arther-linux /]# curl 10.211.55.3:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
	...
# 连上了
Containe模式

​ 这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。 新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个 容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过 lo 网卡设备通信。

​ 产生的网络名称空间也尽不相同,意味着容器的网络资源彼此隔离。

# 创建test01容器
[root@arther-linux /]# docker run -itd --name test01 busybox
Unable to find image 'busybox:latest' locally
Trying to pull repository docker.io/library/busybox ... 
latest: Pulling from docker.io/library/busybox
5f5dd3e95e9f: Pull complete 
Digest: sha256:9f1c79411e054199210b4d489ae600a061595967adb643cd923f8515ad8123d2
Status: Downloaded newer image for docker.io/busybox:latest
40f28e664891327b410b96d0321afd4039aee8190b80f6112728421662f87c4c

# 通过--network将容器2的网络模式设置为contain模式,即网卡配置完全与test01一样
[root@arther-linux /]# docker run -itd --name test02 --network "container:test01" busybox
c351447f5134383178788c16f1dbc231d72e73932c5cc42eb22bb241bbcf3667

# 比对两者的网卡配置
[root@arther-linux /]# docker exec -it test02 sh
/ # ifconfig 
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:06  
          inet addr:172.17.0.6  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:6/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:656 (656.0 B)  TX bytes:656 (656.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

[root@arther-linux /]# docker exec -it test01 sh
/ # ifconfig 
eth0      Link encap:Ethernet  HWaddr 02:42:AC:11:00:06  
          inet addr:172.17.0.6  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:acff:fe11:6/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:656 (656.0 B)  TX bytes:656 (656.0 B)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
              
# 简单理解相当于test01给test02开了一个热点,test02完全以test01的网卡配置连上网。
# 而test01则用了默认的虚拟docker容器网桥的方式。(bridge网络模式)
none 模式

使用 none 模式,Docker 容器拥有自己的 Network Namespace,但是,并不为 Docker 容器进行任何网络 配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置IP 等。

这种网络模式下容器只有 lo 回环网络,没有其他网卡。none 模式可以在容器创建时通过--network=none 来指定。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。

[root@arther-linux /]# docker run -itd --name test03 --network none busybox
8289abbbcce7f92d58c2cf7335aa1843d2b337820a9e93150b041de173b42f06
[root@arther-linux /]# docker exec -it test03 sh
/ # ifconfig 
lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
# 只有本地的Ip地址的配置信息
bridge模式

​ 当Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。

​ 从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡 veth pair 设备,Docker 将 veth pair 设备的一段放在新创建的容器中,并命名为eth0 (容器的网卡),另一端放在主机中,以 vethxxx 这样类似的名字命名,并将这个网络设备加入到 docker0 网桥中。可以通过 brctl show 命令查看。

​ 生成的容器的网络名称空间不是同一个,是自己单独的网络空间,彼此的网络资源的是隔离的。

[root@arther-linux /]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242310e39ed	no		veth3ce4ad4
							veth644e1ad
							vethb409f72
							vetheb71c43
							vethf614949

​ bridge 模式是 docker 的默认网络模式,不写--net 参数,就是 bridge 模式。使用 docker run -p 时,docker实际是在 iptables 做了 DNAT 规则,实现端口转发功能。可以使用 iptables -t nat -vnL 查看。

​ 但是只能实现宿主机中容器之间的联系,如果需要放上公网,可以在浏览器上访问到,需要-p或-P映射默认端口。

[root@arther-linux /]# 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 pfifo_fast state UP group default qlen 1000
    link/ether 00:1c:42:ea:4f:e1 brd ff:ff:ff:ff:ff:ff
    inet 10.211.55.3/24 brd 10.211.55.255 scope global noprefixroute dynamic eth0
       valid_lft 1109sec preferred_lft 1109sec
3: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 52:54:00:84:eb:38 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever
4: virbr0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast master virbr0 state DOWN group default qlen 1000
    link/ether 52:54:00:84:eb:38 brd ff:ff:ff:ff:ff:ff
5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:31:0e:39:ed brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:31ff:fe0e:39ed/64 scope link 
       valid_lft forever preferred_lft forever
67: veth644e1ad@if66: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 7a:bc:96:53:eb:9d brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::78bc:96ff:fe53:eb9d/64 scope link 
       valid_lft forever preferred_lft forever
69: vethb409f72@if68: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether c6:54:a5:51:f4:08 brd ff:ff:ff:ff:ff:ff link-netnsid 1
    inet6 fe80::c454:a5ff:fe51:f408/64 scope link 
       valid_lft forever preferred_lft forever
71: veth3ce4ad4@if70: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 82:a4:55:a8:8f:9c brd ff:ff:ff:ff:ff:ff link-netnsid 2
    inet6 fe80::80a4:55ff:fea8:8f9c/64 scope link 
       valid_lft forever preferred_lft forever
73: vetheb71c43@if72: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether ba:00:f8:28:09:81 brd ff:ff:ff:ff:ff:ff link-netnsid 3
    inet6 fe80::b800:f8ff:fe28:981/64 scope link 
       valid_lft forever preferred_lft forever
75: vethf614949@if74: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether be:d6:4d:59:70:ac brd ff:ff:ff:ff:ff:ff link-netnsid 4
    inet6 fe80::bcd6:4dff:fe59:70ac/64 scope link 
       valid_lft forever preferred_lft forever
77: veth1079c8b@if76: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 46:56:7e:68:87:b3 brd ff:ff:ff:ff:ff:ff link-netnsid 5
    inet6 fe80::4456:7eff:fe68:87b3/64 scope link 
       valid_lft forever preferred_lft forever
      
# 在容器内
[root@arther-linux /]# docker exec -it test04 sh
/ # ping 172.17.0.1
PING 172.17.0.1 (172.17.0.1): 56 data bytes
# 自环


  • 查看网桥

    [root@arther-linux ~]# docker network ls
    NETWORK ID          NAME                DRIVER              SCOPE
    9fbb16915c1c        bridge              bridge              local
    4642eeb296dd        host                host                local
    ad403a4e2146        none                null                local
    
  • 创建网桥

    [root@arther-linux ~]# docker network create oldboy
    89568ea31576582e9454d613df96ca59813238330ca3cd71d3889a0a92d549bb
    
  • 清理网桥

    [root@arther-linux ~]# docker network prune 
    WARNING! This will remove all networks not used by at least one container.
    Are you sure you want to continue? [y/N] y
    Deleted Networks:
    oldboy
    
    # 不会清理默认网桥,只会清理自己自定义然后没有工作的(即没有生成转发容器)的网桥
    
  • 删除网桥

    [root@arther-linux ~]# docker network rm oldboy
    oldboy
    

五 Dockerfile 构建镜像

​ Dockerfile 由一行行命令语句组成,并且支持以 # 开头的注释行,一般而言,Dockerfile 主体内容分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。

​ Dockerfile 以从上到下的顺序运行Dockerfile 的指令。为了指定基本镜像,第一条指令必须是FROM。一个生命以 # 字符开头则被视为注释。可以在Docker文件中使用RUN,CMD,FROM,EXPOSE,ENV 等指令。

1 FROM:指定基础镜像,必须为第一个命令

格式:
		FROM <image> 
  	FROM <image>:<tag> 
    FROM <image>@<digest> 
示例: FROM mysql:5.6 
注: 	tag 或 digest 是可选的,如果不使用这两个值时,会使用 latest 版本的基础镜像

2 MAINTAINER:维护者信息

格式:
		MAINTAINER <name> 
示例:
		MAINTAINER Jasper Xu 
  	MAINTAINER sorex@163.com 
    MAINTAINER Jasper Xu <sorex@163.com>

3 RUN:构建镜像时执行的命令

RUN 用于在镜像容器中执行命令,其有以下两种命令执行方式: 
shell 执行 
格式:
		RUN <command> 
exec 执行 
格式:
		RUN ["executable", "param1", "param2"] 
  
示例:
		RUN ["executable", "param1", "param2"] 
  	RUN apk update RUN ["/etc/execfile", "arg1", "arg1"] 
    注: RUN 指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建 时指定--no-cache 参数,如:docker build --no-cache

4 ADD:将本地文件添加到容器中

tar 类型文件会自动解压(网络压缩资源不会被解压)

格式:
  ADD <src>... <dest> 
  ADD ["<src>",... "<dest>"] 用于支持包含空格的路径 
  
示例:
  ADD hom* /mydir/ 				# 添加所有以"hom"开头的文件 
  ADD hom?.txt /mydir/ 		# ? 替代一个单字符,例如:"home.txt" 
  ADD test relativeDir/ 	# 添加 "test" 到 `WORKDIR`/relativeDir/ 
  ADD test /absoluteDir/  # 添加 "test" 到 /absoluteDir/

5 COPY:功能类似 ADD,但是是不会自动解压文件,也不能访问网络资源

指令:COPY 
功能描述:复制文件到镜像中 
语法:COPY < src>… < dest>|[“< src>”,… “< dest>”] 
提示:指令逻辑和 ADD 十分相似,同样 Docker Daemon 会从编译目录寻找文件或目录,dest 为镜像中的绝 对路径或者相对于 WORKDIR 的路径

6 CMD:构建容器后调用,也就是在容器启动时才进行调用

格式:
	CMD ["executable","param1","param2"] (执行可执行文件,优先) 
  CMD ["param1","param2"] (设置了 ENTRYPOINT,则直接调用 ENTRYPOINT 添加参数) 
  CMD command param1 param2 (执行 shell 内部命令) 
  
示例:
	CMD echo "This is a test." | wc - 
  CMD ["/usr/bin/wc","--help"]注: CMD 不同于 RUN,CMD 用于指定在容器启动时所要执行的 命令,而 RUN 用																	 于指定镜像构建时所要执行的命令。

7 LABEL:用于为镜像添加元数据

格式:
		LABEL <key>=<value> <key>=<value> <key>=<value> ... 
  
示例:
		LABEL version="1.0" description="这是一个 Web 服务器" by="IT 笔录" 
  
注:
		使用 LABEL 指定元数据时,一条 LABEL 指定可以指定一或多条元数据,指定多条元数据时不同元数据之间 通过空格分隔。推荐将所有的元数据通过一条 LABEL 指令指定,以免生成过多的中间镜像。

8 ENV:设置环境变量

格式:
		ENV <key> <value> #<key>之后的所有内容均会被视为其<value>的组成部分,因此,一次只能设置 一个变量ENV <key>=<value> ... #可以设置多个变量,每个变量为一个
  	"<key>=<value>"的键值对,如果 <key>中包含空格,可以使用\来进行转义,也可以通过""来进行标示;另外,反斜线也可以用于续行 示例:
    ENV myName John Doe 
    ENV myDog Rex The Dog 
    ENV myCat=fluffy

9 EXPOSE:指定于外界交互的端口

格式:
		EXPOSE <port> [<port>...] 
示例:
		EXPOSE 80 443 
  	EXPOSE 8080 
    EXPOSE 11211/tcp 11211/udp 
    
注: 
		EXPOSE 并不会让容器的端口访问到主机。要使其可访问,需要在 docker run 运行容器时通过-p 来 发布这些端口,或通过-P 参数来发布 EXPOSE 导出的所有端口

10 VOLUME:用于指定持久化目录

格式:
		VOLUME ["/path/to/dir"] 
  
示例:
		VOLUME ["/data"] 
  	VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"] 
    
注: 一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能: 
1 卷可以容器间共享和重用 
2 容器并不一定要和其它容器共享卷 
3 修改卷后会立即生效 
4 对卷的修改不会对镜像产生影响 
5 卷会一直存在,直到没有任何容器在使用它

11 WORKDIR:工作目录,类似于 cd 命令

格式:
		WORKDIR /path/to/workdir 
  
示例:
		WORKDIR /a (这时工作目录为/a) 
  	WORKDIR b (这时工作目录为/a/b) 
    WORKDIR c (这时工作目录为/a/b/c) 
    
注: 
		通过 WORKDIR 设置工作目录后,Dockerfile 中其后的命令 RUN、CMD、ENTRYPOINT、ADD、COPY 等命令都会在该目录下执行。在使用 docker run 运行容器时,可以通过-w 参数覆盖构建时所设置的工作目录。

12 ARG:用于指定传递给构建运行时的变量

格式:
		ARG <name>[=<default value>] 
  
示例:
		ARG site ARG build_user=www

13 ONBUILD:用于设置镜像触发器

格式: ONBUILD [INSTRUCTION] 
示例:
			ONBUILD ADD . /app/src 
  		ONBUILD RUN /usr/local/bin/python-build --dir /app/src 
    
注: 
			当所构建的镜像被用做其它镜像的基础镜像,该镜像中的触发器将会被钥触发

14 Dockerfile 构建镜像案例

制作镜像

# 写Dockerfile
[root@arther-linux test]# cat Dockerfile 

# 指定基础镜像
FROM python:3.6.12

# 安装django
RUN pip3 install django==2.2.2 -i https://pypi.douban.com/simple/

# 创建app项目
RUN django-admin startproject app

# 创建application
RUN cd /app && django-admin startapp docker

# 启动
CMD cd /app && python3 manage.py runserver 0.0.0.0:8000



[root@arther-linux /]# docker build -t test/busybox:v1 .
Error checking context: 'no permission to read from '/media/psf/Home/Library/Preferences/com.apple.AddressBook.plist''.
# 不能写绝对路径,要相对路径


# 会自动执行Dockerfile中的代码
[root@arther-linux test]# docker build -t test:v1 .
Sending build context to Docker daemon 718.4 MB
Step 1/5 : FROM python:3.6.12
 ---> 178f37a5a906
Step 2/5 : RUN pip3 install django==2.2.2 -i https://pypi.douban.com/simple/
 ---> Running in 15cb7581d493

Looking in indexes: https://pypi.douban.com/simple/
Collecting django==2.2.2
  Downloading https://pypi.doubanio.com/packages/eb/4b/743d5008fc7432c714d753e1fc7ee56c6a776dc566cc6cfb4136d46cdcbb/Django-2.2.2-py3-none-any.whl (7.4 MB)
Collecting pytz
  Downloading https://pypi.doubanio.com/packages/12/f8/ff09af6ff61a3efaad5f61ba5facdf17e7722c4393f7d8a66674d2dbd29f/pytz-2020.4-py2.py3-none-any.whl (509 kB)
Collecting sqlparse
  Downloading https://pypi.doubanio.com/packages/14/05/6e8eb62ca685b10e34051a80d7ea94b7137369d8c0be5c3b9d9b6e3f5dae/sqlparse-0.4.1-py3-none-any.whl (42 kB)
Installing collected packages: sqlparse, pytz, django
Successfully installed django-2.2.2 pytz-2020.4 sqlparse-0.4.1
 ---> 01fa3f47e5e8
Removing intermediate container 15cb7581d493
Step 3/5 : RUN django-admin startproject app
 ---> Running in 0e999307c880

 ---> 43939255f0b9
Removing intermediate container 0e999307c880
Step 4/5 : RUN cd /app && django-admin startapp docker
 ---> Running in fe0ae86cb44a

 ---> cbf131ce037d
Removing intermediate container fe0ae86cb44a
Step 5/5 : CMD cd /app && python3 manage.py runserver 0.0.0.0:8000
 ---> Running in 22c3f43f2dfa
 ---> 02429b584fa7
Removing intermediate container 22c3f43f2dfa
Successfully built 02429b584fa7


# 生成容器
[root@arther-linux test]# docker run -d -it test:v1
693423b16b04871a70b20df865aa730729154ec07a15e125fe1f9cfe6433774b

[root@arther-linux test]# docker exec -it  pensive_jang bash

root@693423b16b04:/usr/local/bin# ls
2to3	     django-admin     easy_install-3.6	idle3.6  pip3.6  pydoc3.6	python3		python3.6-config   pyvenv      wheel
2to3-3.6     django-admin.py  idle		pip	 pydoc	 python		python3-config	python3.6m	   pyvenv-3.6
__pycache__  easy_install     idle3		pip3	 pydoc3  python-config	python3.6	python3.6m-config  sqlformat

制作镜像,在容器中设置nginx反向代理

http://nginx.org/en/linux_packages.html#RHEL-CentOS

# 在此网站获取下载nginx的步骤

# 在此文件路径下写入官网提供的nginx配置
[root@arther-linux ~]# touch /etc/yum.repos.d/nginx.repo
[root@arther-linux ~]# vim /etc/yum.repos.d/nginx.repo

# 生成yum缓存
[root@arther-linux ~]# yum makecache 

# 正式安装naginx
[root@arther-linux ~]# yum install nginx -y


# 以之前定义的镜像为基本生成容器,映射
[root@arther-linux ~]# docker run -d -p 8080:8000 test:v1

======配置代理=======
'''
反向代理,以服务器为主,服务器打集群后下有多台主机,用户不需知道哪一台的主机IP,只需知道主服务器IP即可访问

'''
# 先清空默认配置
[root@arther-linux conf.d]# >default.conf 


upstream django {
    server 127.0.0.1:8080;   # 代理服务器的IP与端口,本机测试的IP地址
}

server {
    listen 80;
    server_name _;
    location / {
        proxy_pass http://django;
        index index.html index.htm;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }}

# 测试配置是否成功
[root@arther-linux conf.d]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
  
# 再启动nginx
[root@arther-linux ~]# nginx -g 'daemon off;'  

# 制作镜像文件Dockerfile
[root@arther-linux ~]# mkdir teach
[root@arther-linux ~]# cd teach
[root@arther-linux teach]# mkdir django
[root@arther-linux teach]# mkdir nginx
[root@arther-linux teach]# cd nginx
[root@arther-linux nginx]# touch Dockerfile
[root@arther-linux nginx]# vim Dockerfile 
============写入文件=============
# 设置基础镜像
FROM centos:7

# 安装yum工具
# 设置基础镜像
FROM centos:7

RUN yum install wget -y

# 换源
RUN mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup

RUN cd /etc/yum.repos.d && wget http://mirrors.163.com/.help/CentOS7-Base-163.repo

RUN mv /etc/yum.repos.d/CentOS7-Base-163.repo /etc/yum.repos.d/CentOS-Base.repo

# 创建nginx源的文件
ADD nginx.repo /etc/yum.repos.d/

# 刷新yum缓存
RUN yum makecache

# 安装yum工具
RUN yum install yum-utils -y

# 安装Nginx
RUN yum install nginx -y

# 复制配置文件
ADD default.conf /etc/nginx/conf.d/

# 设置启动命令
CMD nginx -g 'daemon off;'                                                                    

===============================
# 换源或是配置不能直接写入,只能用mv指令移入
[root@arther-linux nginx]# vim nginx.repo
# 把源的配置写入,方便之后制作镜像时写入的操作

[root@arther-linux nginx]# vim default.conf
upstream django {
    server django:8000;       # 此时在容器里执行,到时候被代理容器命名为django,8000端口对应,django	
}															# Dockerfile 中的 0.0.0.0:8000

server {
    listen 80;
    server_name _;
    location / {
        proxy_pass http://django;
        index index.html index.htm;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }}


[root@arther-linux ~]# docker network create oldboy

# 执行制作镜像命令
[root@arther-linux ~]# docker build -t nginx:v1 . -f ~/teach/nginx/Dockerfile
# -f指定了寻找Dockerfile在当前文件夹
[root@arther-linux ~]# docker build -t django -f Dockerfile .

# 用同一个网桥启动容器
docker run -dit --name nginx --network oldboy nginx:v1
# 制作容器时,需要命名为之前default.conf 设置的代理的容器名
docker run -dit --name nginx --network oldboy django:latest # Dockerfile在上一部分已写好

# 查看是否运行
[root@arther-linux ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
07c6c8459f15        nginx:v1            "/bin/sh -c 'nginx -…"   3 hours ago         Up 3 hours                              nginx
04f96e388361        django:latest       "/bin/sh -c 'cd /app…"   3 hours ago         Up 3 hours                              django  
  
  
# 测试连接
[root@arther-linux ~]# docker exec -it nginx bash
[root@07c6c8459f15 /]# ping django
PING django (172.18.0.2) 56(84) bytes of data.
64 bytes from django.oldboy (172.18.0.2): icmp_seq=1 ttl=64 time=0.041 ms
64 bytes from django.oldboy (172.18.0.2): icmp_seq=2 ttl=64 time=0.050 ms
64 bytes from django.oldboy (172.18.0.2): icmp_seq=3 ttl=64 time=0.066 ms
  

推荐阅读