## docker容器

### 1：什么是容器

容器就是在隔离的环境运行的一个进程，如果进程停止，容器就会销毁。隔离的环境拥有自己的系统文件，ip地址，主机名等。

程序：代码，命令
进程：正在运行的程序
容器的系统文件就是宿主机的某一个目录



### 2：容器和虚拟化的区别

![image-20221106231941897](https://note-1308251438.cos.ap-guangzhou.myqcloud.com/typora/202211062319964.png)



Linux容器技术，容器虚拟化和kvm虚拟化的区别
kvm虚拟化：需要硬件的支持，需要模拟硬件，可以运行不同的操作系统，启动时间分钟级

Linux开机启动流程：
BIOS开机硬件自检
根据BIOS设置的优先启动项boot 网卡 硬盘 U盘 光驱
读取mbr引导   UEFI(gpt分区)    mbr硬盘分区信息，内核加载路径
加载内核
启动第一个进程init   systemd
系统初始化完成
运行服务
。。。

容器：共用宿主机内核，容器的第一个进程直接运行服务，损耗少，启动快，性能高
容器虚拟化：不需要硬件的支持，不需要模拟硬件，共用宿主机的内核，启动时间秒级(没有开机流程)



![image-20221107001014175](https://note-1308251438.cos.ap-guangzhou.myqcloud.com/typora/202211070010264.png)



- 虚拟机（重量级）
  - **基础设施(Infrastructure)**：它可以是你的个人电脑，数据中心的服务器，或者是云主机。
  - **虚拟机管理系统(Hypervisor)**：利用Hypervisor，可以在主操作系统之上运行多个不同的从操作系统。类型1的Hypervisor有支持MacOS的HyperKit，支持Windows的Hyper-V、Xen以及KVM。类型2的Hypervisor有VirtualBox和VMWare workstation。
  - **客户机操作系统(Guest Operating System)**：假设你需要运行3个相互隔离的应用，则需要使用Hypervisor启动3个客户机操作系统，也就是3个虚拟机。这些虚拟机都非常大，也许有700MB，这就意味着它们将占用2.1GB的磁盘空间。更糟糕的是，它们还会消耗很多CPU和内存。
  - **各种依赖**：每一个客户机操作系统都需要安装许多依赖。如果你的应用需要连接PostgreSQL的话，则需要安装libpq-dev；如果你使用Ruby的话，应该需要安装gems；如果使用其他编程语言，比如Python或者Node.js，都会需要安装对应的依赖库。
  - **应用**：安装依赖之后，就可以在各个客户机操作系统分别运行应用了，这样各个应用就是相互隔离的
- 容器（轻量级）
  - **基础设施(Infrastructure)**：它可以是你的个人电脑，数据中心的服务器，或者是云主机。
  - **主操作系统(Host Operating System)**：所有主流的Linux发行版都可以运行Docker。对于MacOS和Windows，也有一些办法”运行”Docker。
  - **Docker守护进程(Docker Daemon)**：Docker守护进程取代了Hypervisor，它是运行在操作系统之上的后台进程，负责管理Docker容器。
  - **各种依赖**：对于Docker，应用的所有依赖都打包在Docker镜像中，Docker容器是基于Docker镜像创建的。
  - **应用**：应用的源代码与它的依赖都打包在Docker镜像中，不同的应用需要不同的Docker镜像。不同的应用运行在不同的Docker容器中，它们是相互隔离的。

总结：
(1) 与宿主机使用同一个内核，性能损耗小；
(2) 不需要指令集模拟；
(3) 容器可以在cpu核心的本地运行指令，不需要任何专门的解释机制；
(4) 避免了准虚拟化和系统调用替换中的复杂性；
(5) 轻量级隔离，在隔离的同时还提供共享机制，以实现容器与宿主机的资源共享

### 3：什么是 Docker

Docker 最初是 dotCloud 公司创始人 Solomon Hykes 在法国期间发起的一个公司内部项目，它是基于 dotCloud 公司多年云服务技术的一次革新，并于 [2013 年 3 月以 Apache 2.0 授权协议开源](https://en.wikipedia.org/wiki/Docker_(software))，主要项目代码在 [GitHub](https://github.com/moby/moby) 上进行维护。Docker 项目后来还加入了 Linux 基金会，并成立推动 [开放容器联盟（OCI）](https://www.opencontainers.org/)。

Docker 自开源后受到广泛的关注和讨论，至今其 GitHub 项目已经超过 4 万 6 千个星标和一万多个 fork。甚至由于 Docker 项目的火爆，在 2013 年底，[dotCloud 公司决定改名为 Docker](https://blog.docker.com/2013/10/dotcloud-is-becoming-docker-inc/)。Docker 最初是在 Ubuntu 12.04 上开发实现的；Red Hat 则从 RHEL 6.5 开始对 Docker 进行支持；Google 也在其 PaaS 产品中广泛应用 Docker。

Docker 使用 Google 公司推出的 [Go 语言](https://golang.org/) 进行开发实现，基于 Linux 内核的 [cgroup](https://zh.wikipedia.org/wiki/Cgroups)，[namespace](https://en.wikipedia.org/wiki/Linux_namespaces)，以及  [AUFS](https://en.wikipedia.org/wiki/Aufs) 类的 [Union FS](https://en.wikipedia.org/wiki/Union_mount) 等技术，对进程进行封装隔离，属于 [操作系统层面的虚拟化技术](https://en.wikipedia.org/wiki/Operating-system-level_virtualization)。由于隔离的进程独立于宿主和其它的隔离的进程，因此也称其为容器。最初实现是基于 [LXC](https://linuxcontainers.org/lxc/introduction/)，从 0.7 版本以后开始去除 LXC，转而使用自行开发的 [libcontainer](https://github.com/docker/libcontainer)，从 1.11 开始，则进一步演进为使用 [runC](https://github.com/opencontainers/runc) 和 [containerd](https://github.com/containerd/containerd)。

Docker 在容器的基础上，进行了进一步的封装，从文件系统、网络互联到进程隔离等等，极大的简化了容器的创建和维护。使得 Docker 技术比虚拟机技术更为轻便、快捷。

传统虚拟机技术是虚拟出一套硬件后，在其上运行一个完整操作系统，在该系统上再运行所需应用进程；而容器内的应用进程直接运行于宿主的内核，容器内没有自己的内核，而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。

**chroot技术**

**新建一个子系统（拥有自己完整的系统文件）**

**参考资料：https://www.ibm.com/developerworks/cn/linux/l-cn-chroot/**





### 4：为什么要使用 Docker

**作为一种新兴的虚拟化方式，Docker 跟传统的虚拟化方式相比具有众多的优势。**

##### 更高效的利用系统资源

由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销，Docker 对系统资源的利用率更高。无论是应用执行速度、内存损耗或者文件存储速度，都要比传统虚拟机技术更高效。因此，相比虚拟机技术，一个相同配置的主机，往往可以运行更多数量的应用。

##### 更快速的启动时间

传统的虚拟机技术启动应用服务往往需要数分钟，而 Docker 容器应用，由于直接运行于宿主内核，无需启动完整的操作系统，因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。

##### 一致的运行环境

开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致，导致有些 bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境，确保了应用运行环境一致性，从而不会再出现 「这段代码在我机器上没问题啊」 这类问题。

##### 持续交付和部署

对开发和运维（DevOps）人员来说，最希望的就是一次创建或配置，可以在任意地方正常运行。

使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员可以通过 Dockerfile 来进行镜像构建，并结合 持续集成(Continuous Integration) 系统进行集成测试，而运维人员则可以直接在生产环境中快速部署该镜像，甚至结合 持续部署(Continuous Delivery/Deployment) 系统进行自动部署。

而且使用 Dockerfile 使镜像构建透明化，不仅仅开发团队可以理解应用运行环境，也方便运维团队理解应用运行所需条件，帮助更好的生产环境中部署该镜像。

##### 更轻松的迁移

由于 Docker 确保了执行环境的一致性，使得应用的迁移更加容易。Docker 可以在很多平台上运行，无论是物理机、虚拟机、公有云、私有云，甚至是笔记本，其运行结果是一致的。因此用户可以很轻易的将在一个平台上运行的应用，迁移到另一个平台上，而不用担心运行环境的变化导致应用无法正常运行的情况。

##### 更轻松的维护和扩展

Docker 使用的分层存储以及镜像的技术，使得应用重复部分的复用更为容易，也使得应用的维护更新更加简单，基于基础镜像进一步扩展镜像也变得非常简单。此外，Docker 团队同各个开源项目团队一起维护了一大批高质量的 官方镜像，既可以直接在生产环境使用，又可以作为基础进一步定制，大大的降低了应用服务的镜像制作成本。

##### 对比传统虚拟机总结

|    特性    |                         容器                          |       虚拟机        |
| :--------: | :---------------------------------------------------: | :-----------------: |
|    启动    |                         秒级                          |       分钟级        |
|  运行形态  | 直接运行于宿主机的内核上，不同容器共享同一个liunx内核 | 运行于Hypervisior上 |
|  硬盘使用  |                      一般为 `MB`                      |     一般为 `GB`     |
|    性能    |                       接近原生                        |        弱于         |
| 系统支持量 |                  单机支持上千个容器                   |     一般几十个      |



![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205282316835.png)



### 5：docker不是完整的虚拟化

不是一个系统而是一个进程组，docker是一个进程（父进程），docker里有很多进程（子进程）。

<font color='red'>**注意：**</font>

<font color='red'>**千万不要误以为Docker就是虚拟机。其实Docker不是虚拟机！**</font>

<font color='red'>**docker是前台运行的需要hold住，也就是command是在前台停留的**</font>

<font color='red'>**docker没有systemd概念**</font>



### 6：docker容器

docker是通过进程虚拟化技术（namespaces及cgroups cpu、内存、磁盘io等）来提供容器的资源隔离与安全保障等。由于Docker通过操作系统层的虚拟化实现隔离，所以Docker容器在运行时，不需要类似虚拟机（VM）额外的操作系统开销，提高资源利用率。
namespace：资源隔离
cgroups：进程的资源限制
kvm：虚拟磁盘文件，资源隔离；资源限制
chroot：提供文件系统
docker：初期把lxc二次开发，libcontainer



docker的主要目标是"Build,Ship and Run any App,Angwhere"，构建，运输，处处运行

**Build once，Run anywhere**  一次构建，处处运行

部署服务，环境问题

docker是一种软件的打包技术



构建：做一个docker镜像
运输：docker pull
运行：启动一个容器
每一个容器，他都有自己的系统文件rootfs

kvm解决了硬件和操作系统之间的依赖
kvm独立的虚拟磁盘，xml配置文件

docker解决了软件和操作系统环境之间的依赖，能够让独立服务或应用程序在不同环境中，得到相同的运行结果。
docker镜像有自己的文件系统。



#### 容器启动运行流程

![image-20221107002206437](https://note-1308251438.cos.ap-guangzhou.myqcloud.com/typora/202211070022527.png)







### 7：Docker镜像

![](https://note-1308251438.cos.ap-guangzhou.myqcloud.com/typora/202206151031058.webp)

#### 镜像原理（镜像文件系统原理）

Docker镜像是有文件系统叠加而成，***最低端是一个引导文件系统，即bootfs。***

Docker镜像的第二层是root文件系统rootfs，它位于引导文件系统bootfs之上。rootfs可以使一种或多种 操作系统，**传统的Linux**系统引导时**root文件系统**最先**以**只读**的方式加载，**引导结束**并完成完整性检查后会切换到**读写模式，<font color='red'>**Docker中root文件系统永远只能是只读状态**</font>，并且Docker利用联合加载(unionmount)技术又会再root文件系统上加载更多的只读文件系统。

当容器启动时，一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”，“容器层”之下的都叫“镜像层”。

Docker将这种文件系统称为镜像，镜像可以叠加，在下方的镜像称为父镜像，最底层的镜像称为基础镜像，当使用一个镜像启动容器时，Docker会在该镜像的最顶层加载一个读写文件系统，在Docker中运行的程序就在这个读写层。

**写时复制：**Docker第一次启动一个容器时，初始的读写层是空的。当文件系统发生变化时，这些变化都会应用到这一层上，如果要修改一个文件，此文件会从下面的只读层复制到读写层，此文件的**只读版本依然存在**，但是会被读写层的副本隐藏。

![img](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205192024532.png)

**联合加载**：指一次同时加载多个文件系统(镜像)，但是再外面只能看到一个文件系统，联合加载会将各层文件系统叠加到一起，这样最终文件系统会包含所有底层的文件和目录。

当一个容器启动后，容器会被移动到内存中，引导文件系统则会被卸载，以留出更多的内存公initrd磁盘镜像使用。

**简单来说docker容器是由镜像的只读层(只读层以下的都归为只读层)和容器赋予的可读可写层组成的，如下图**

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205192029420.png)

### 8：镜像、容器、仓库

#### 镜像

Docker的镜像是一个只读的模板，一个独立的文件系统，包括运行容器所需的数据，可以用来创建新的容器。

Docker的镜像相当于centos操作系统的iso安装包，ISO镜像的内容是固定的，不会发生改变，可以重复使用。

#### 容器

Docker镜像生成出来的东西，我们就叫他它“容器”

#### 仓库

仓库支持的操作类似git，当用户创建了自己的镜像之后就可以使用 push 命令将它上传到公有或者私有仓库，这样下次在另外一台机器上使用这个镜像时候，只需要从仓库上 pull 下来就可以了。

类似于，将某项目模块打成jar包，然后上传到私有或者公有的maven仓库，然后在其他的所有支持maven环境的机器上，都可以拉取这个jar进行使用。

Docker Hub是由Docker公司负责维护的公共注册中心，包含大量的容器镜像，Docker工具默认从这个公共镜像库下载镜像。地址：https://hub.docker.com/explore



**简单来说**

**镜像：启动容器的模板**

**仓库：保存镜像的地方**

**容器：对外提供服务的实例**





### 实验环境

| 主机名 |     IP地址     | 备注 |
| :----: | :------------: | :--: |
| docker | 192.168.188.70 |      |





## Docker安装

#### 环境准备

```shell
[root@docker ~]# yum install -y wget
[root@docker ~]# cd /etc/yum.repos.d/
[root@docker yum.repos.d]# mkdir bak
[root@docker yum.repos.d]# mv ./* bak/
```

```shell
# 准备Base源
[root@docker yum.repos.d]# wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo

[root@docker ~]# yum makecache
```



#### 开始安装

**打开阿里源的docker-ce源里面也有教程**

```shell
# step 1: 安装必要的一些系统工具
[root@docker ~]# yum install -y yum-utils device-mapper-persistent-data lvm2

# Step 2: 添加软件源信息
[root@docker ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# Step 3
[root@docker ~]# sed -i 's+download.docker.com+mirrors.aliyun.com/docker-ce+' /etc/yum.repos.d/docker-ce.repo

# Step 4: 更新并安装Docker-CE
[root@docker ~]# yum makecache fast
[root@docker ~]# yum -y install docker-ce-18.06.3.ce-3.el7

# Step 4: 开启Docker服务
[root@docker ~]# service docker start
[root@docker ~]# systemctl enable docker

# 注意：
# 官方软件源默认启用了最新的软件，您可以通过编辑软件源的方式获取各个版本的软件包。例如官方并没有将测试版本的软件源置为可用，您可以通过以下方式开启。同理可以开启各种测试版本等。
# vim /etc/yum.repos.d/docker-ce.repo
#   将[docker-ce-test]下方的enabled=0修改为enabled=1
#
# 安装指定版本的Docker-CE:
# Step 1: 查找Docker-CE的版本:
# yum list docker-ce.x86_64 --showduplicates | sort -r
#   Loading mirror speeds from cached hostfile
#   Loaded plugins: branch, fastestmirror, langpacks
#   docker-ce.x86_64            17.03.1.ce-1.el7.centos            docker-ce-stable
#   docker-ce.x86_64            17.03.1.ce-1.el7.centos            @docker-ce-stable
#   docker-ce.x86_64            17.03.0.ce-1.el7.centos            docker-ce-stable
#   Available Packages
# Step2: 安装指定版本的Docker-CE: (VERSION例如上面的17.03.0.ce.1-1.el7.centos)
# sudo yum -y install docker-ce-[VERSION]
```



### 镜像加速(可以指向个人仓库或企业仓库)

**这里采用阿里云的镜像加速，https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors**

```shell
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://2l058lvr.mirror.aliyuncs.com"]
}
EOF
systemctl daemon-reload
systemctl restart docker
```



### 

## Docker基本操作

[官网操作文档：](https://docs.docker.com/engine/reference/commandline/docker/)https://docs.docker.com/engine/reference/commandline/docker/



### 查看docker版本号

```shell
[root@docker ~]# docker version   # 查看docker版本号
```

### 查看镜像信息 images

```shell
# 查看镜像信息 images
[root@docker ~]# docker images ls
REPOSITORY   TAG       IMAGE ID   CREATED   SIZE
[root@docker ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
hello-world   latest    feb5d9fea6a5   7 months ago   13.3kB


# 该表格包含了5列，含义如下：
1. REPOSITORY：镜像所属仓库名称。
2.TAG：镜像标签。默认是latest，表示最新。
3.IMAGE ID：镜像ID，表示镜像唯一标识。
4.CREATED：镜像创建时间。
5.SIZE：镜像大小。
```

### 查看容器 ps

```shell
# 查看当前启动的容器，二选一
[root@docker ~]# docker container ls
[root@docker ~]# docker ps（只列出运行的容器）
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

# 列出所有容器，包括未运行的容器
[root@docker ~]# docker ps -a


# 该表格包含了七列，含义如下：
1.CONTAINER_ID：表示容器ID。
2.IMAGE：表示镜像名称。
3.COMMAND：表示启动容器时运行的命令。运行的时候必须使用，不然可能起不来
4.CREATED：表示容器的创建时间。
5.STATUS：表示容器运行的状态。Up表示运行中，Exited表示已停止。
6.PORTS：表示容器对外的端口号。
7.NAMES：表示容器名称。该名称默认由Docker自动生成，也可使用docker run命令的–name选项自行指定。
```

### 镜像拉取centos和ubuntu

```shell
# pull命令可以从远程仓库拉取镜像，如果本地仓库已经存在该镜像，则会更新，默认源是Docker Hub，不指定版本时默认为latest版本
[root@docker ~]# docker pull centos:7   # 拉取指定版本的centos
[root@docker ~]# docker pull ubuntu     # 拉取ubuntu
[root@docker ~]# docker pull hello-world	#最小的例子，一般用来监测是否正常安装成功docker
```



### 容器运行镜像

```shell
[root@docker ~]# docker run hello-world
```

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205192059676.png)

```shell
# 运行centos:7
[root@docker ~]# docker images
REPOSITORY    TAG       IMAGE ID       CREATED        SIZE
ubuntu        latest    ba6acccedd29   7 months ago   72.8MB
hello-world   latest    feb5d9fea6a5   7 months ago   13.3kB
centos        7         eeb6ee3f44bd   8 months ago   204MB
[root@docker ~]# docker run eeb6ee3f44bd   # docker run 指定镜像ID  容器运行镜像，前台运行。（备注生产中调试用）
[root@docker ~]# docker ps   # 运行完上一条命令查看容器，发现没有
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
[root@docker ~]# docker ps -a   # 要指定command，可以看到/bin/bash了一下，容器刷新一下就挂掉了
CONTAINER ID   IMAGE          COMMAND       CREATED          STATUS                      PORTS     NAMES
45861729009d   eeb6ee3f44bd   "/bin/bash"   22 seconds ago   Exited (0) 20 seconds ago             nifty_hermann
354e1fb5eb93   hello-world    "/hello"      36 hours ago     Exited (0) 36 hours ago               infallible_aryabhata

# 正确使用
[root@docker ~]# docker run -it eeb6ee3f44bd /bin/bash #分配伪终端启动容器。如果默认命令可以hold住退出容器，容器不消亡。如果hold 不住，则容器消亡。
[root@9954d6e3cb32 /]#     # 可以看到主机名变成了容器ID，证明成功进入
# 在容器内使用df -h 、free -h、lscpu等命令查看得到的都是宿主机的资源
# 可以使用ip a查看ip进行判断
[root@9954d6e3cb32 /]# yum -y install net-tools
[root@9954d6e3cb32 /]# ifconfig   # 会发现IP地址是172开头的，同时宿主机也有一张网卡容器的IP地址就是来源它；如果容器存活，宿主机还有一张对应的网卡，反之
[root@9954d6e3cb32 /]# exit   # 退出容器，不存活


# 错误后台使用
[root@docker ~]# docker run -d eeb6ee3f44bd /bin/bash   # 输出结果看起来启动了，实际并没有；有一些可以不接command，因为容器里面已经写好
68928d357d8bd801d4442df50d5c3f28c2a245c3e8864268c74055c8aafe1b74
[root@docker ~]# docker ps   # 因为后台运行/bin/bash就是刷新一下重新分配一个终端，所以容器就挂掉了
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

# 应挂载文件与开放端口
[root@docker ~]# docker run -d eeb6ee3f44bd   # 后台运行镜像容器，一般还需要开放端口和挂载文件等
```

### 删除容器

```shell
# 单一删除
[root@docker ~]# docker ps -a

[root@docker ~]# docker rm 354e1fb5eb93   # 通过容器id来删除容器
354e1fb5eb93

[root@docker ~]# docker rm awesome_dirac   # 通过容器名字来删除容器
awesome_dirac


# 批量删除
[root@docker ~]# docker ps -a -q   # 批量显示容器id
9954d6e3cb32
45861729009d
[root@docker ~]# docker rm `docker ps -q -a`   # 通过id批量删除容器
9954d6e3cb32
45861729009d
```

### 查看容器详细信息

```shell
[root@docker ~]# docker run -d eeb6ee3f44bd   # 返回容器ID
af0ba7c7c3a7086c0b3d9623e90acae36660f6ff2df467d14a59edbe3eefe96f
[root@docker ~]# docker inspect af0ba7   # 接容器ID前几位数即可，但并没有运行起来，所以没有网络信息，因为docker是前台运行的，前文有说到
```

### 镜像仓库

**使用阿里云的镜像仓库，请自行创建好(容器镜像服务https://cr.console.aliyun.com/cn-hangzhou/instances)**

```shell
# 举例
# 推送
docker login --username=注册的阿里云仓库账号或者默认dockerhub  registry.cn-shenzhen.aliyuncs.com（跟仓库域名）
docker tag 镜像id registry.cn-shenzhen.aliyuncs.com/adif0028（账号空间）/centos（账号仓库）:[自定义镜像版本号]
docker push registry.cn-shenzhen.aliyuncs.com/adif0028/centos:[自定义镜像版本号]

# 通过docker ps查看会发现多了一个相当于软链接的镜像

# 拉取取决于是公开还是私有，在阿里云选择不同的网络拉取
```

![image-20221107154026902](https://note-1308251438.cos.ap-guangzhou.myqcloud.com/typora/202211071540031.png)



### 删除镜像

```shell
# 单一删除

# 删除hello-wold镜像
[root@docker ~]# docker images

[root@docker ~]# docker rmi feb5d9fea6a5   # docker rmi 镜像id/镜像名 (备注如果镜像间有父子镜像关系是不能被删除的，已经被容器运行起来的镜像也不允许删除)


# 批量删除
[root@docker ~]# docker images -q   # 显示所有镜像ID
ba6acccedd29
eeb6ee3f44bd
[root@docker ~]# docker rmi $(docker images -q)   # 通过镜像id批量删除镜像
```

### 搜索镜像

```shell
[root@docker ~]# docker search nginx
NAME      DESCRIPTION      STARS     OFFICIAL   AUTOMATED

# 表格包含五列，含义如下：
1.NAME：镜像仓库名称。
2.DESCRIPTION：镜像仓库描述。
3.STARS：镜像仓库收藏数，表示该镜像仓库的受欢迎程度，类似于GitHub的Stars。
4.OFFICAL：表示是否为官方仓库，该列标记为[OK]的镜像均由各软件的官方项目组创建和维护。由结果可知，java这个镜像仓库是官方仓库，而其他的仓库都不是镜像仓库。
5.AUTOMATED：表示是否是自动构建的镜像仓库。


# 选用镜像建议
1.优先考虑官方的
2.Stars数多的



# 运行一个nginx容器：
# pull一个nginx镜像注意选择合适版本
[root@docker ~]# docker pull nginx
[root@docker ~]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED        SIZE
nginx        latest    605c77e624dd   4 months ago   141MB
ubuntu       latest    ba6acccedd29   7 months ago   72.8MB
centos       7         eeb6ee3f44bd   8 months ago   204MB

# 拉取一个最小系统镜像alpine
[root@docker ~]# docker pull alpine
[root@docker ~]# docker pull nginx:stable-alpine   # 拉取以alpine为底层镜像的nginx
[root@docker ~]# docker images
REPOSITORY   TAG             IMAGE ID       CREATED        SIZE
nginx        latest          605c77e624dd   4 months ago   141MB
alpine       latest          c059bfaa849c   5 months ago   5.59MB
nginx        stable-alpine   373f8d4d4c60   6 months ago   23.2MB
ubuntu       latest          ba6acccedd29   7 months ago   72.8MB
centos       7               eeb6ee3f44bd   8 months ago   204MB
[root@docker ~]# docker run -d -p 80:80 373f8d4d4c60   # 启动以alpine为底层镜像的nginx，-p端口映射，宿主机的80映射到容器里面的80
f8c67ad2a29bb87f45a2c5f7339e390efc72fd72c91959a440431e0768025f9d
[root@docker ~]# docker ps   # 检查
# 浏览器打开宿主机IP:80

```

### 进入已经运行的容器

```
[root@docker ~]# docker exec -it f8c67ad2a29b /bin/sh   # alpine没有bash的只有sh
/ # exit
[root@docker ~]#       # 退出后容器仍然存活 

[root@docker ~]# docker ps   # 检查发现command是容器里面写好的一个脚本




#进入容器：
#     进入容器(目的，调试，排错)
#     	docker exec  （会分配一个新的终端tty）
#		docker exec [OPTIONS] CONTAINER COMMAND [ARG...]		
#     docker exec -it  容器id或容器名字 /bin/bash（/bin/sh）
```



### docker attach（使用同一个终端）

```shell
# attach是同时操作同步的
# docker attach :连接到正在运行中的容器

# 终端1
[root@docker ~]# docker images
REPOSITORY   TAG             IMAGE ID       CREATED        SIZE
nginx        latest          605c77e624dd   4 months ago   141MB
alpine       latest          c059bfaa849c   5 months ago   5.59MB
nginx        stable-alpine   373f8d4d4c60   6 months ago   23.2MB
ubuntu       latest          ba6acccedd29   7 months ago   72.8MB
centos       7               eeb6ee3f44bd   8 months ago   204MB

[root@docker ~]# docker run -it ba6acccedd29
root@5eb73951fddc:/#

# 终端2
[root@docker ~]# docker attach 5eb73951fddc   # 接容器ID


# exec是重新分配一个终端，attach是使用同一个终端

#     docker attach（使用同一个终端）
#           docker attach [OPTIONS] CONTAINER 
#     nsenter(安装yum install -y util-linux 弃用)
```

### 宿主机挂载文件进容器

```shell
# 拉去一个mysql5.7的容器
[root@docker ~]# docker pull mysql:5.7
[root@docker ~]# docker images   # 检查

[root@docker ~]# yum install -y lsof   # 安装lsof
[root@docker ~]# lsof -i :3306   # 检查3306端口是否被占用

# -e 传入一个环境变量，可以是字符串也可以是文件
[root@docker ~]# docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD="123456" c20987f18b13
[root@docker ~]# docker ps   # 验证
# 使用navicat连接验证
```
 ![2022-05-21_104502](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205211045531.png)

 ![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205211045524.png)



```shell
# 暴力结束所以运行中的容器（慎重）
[root@docker ~]# docker rm -f `docker ps -a -q`   # 使用-f参数

# 在宿主机创建挂载数据库文件目录
[root@docker ~]# mkdir /opt/mysql_data

# 使用-v参数，宿主机的挂载源挂到容器里面挂载点上；对应容器mysql就是/var/lib/mysql，这里是容器内生成数据的目录
[root@docker ~]# docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD="123456" -v /opt/mysql_data/:/var/lib/mysql c20987f18b13

[root@docker ~]# docker ps   # 验证

# 测试把容器删掉，宿主机上数据目录里面的数据是否还在
[root@docker ~]# cd /opt/mysql_data/
[root@docker mysql_data]# ls
[root@docker mysql_data]# docker stop e05cb1581c9d   # 停止容器
e05cb1581c9d
[root@docker mysql_data]# docker rm e05cb1581c9d
e05cb1581c9d
[root@docker mysql_data]# docker ps -a
[root@docker mysql_data]# ls   # 仍存在


# 所以当把数据目录放在宿主机上是可以做到防止重要数据丢失，可是生产上还是不建议使用容器数据库
# 数据库容器存货时，宿主机数据库目录会发现有一个临时文件ibtmp1，容器消亡后临时文件z不存在
```

```shell
# 进入容器新创库删掉看看是否会初始化覆盖掉造成数据丢失
[root@docker mysql_data]# docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD="123456" -v /opt/mysql_data/:/var/lib/mysql c20987f18b13
db2a557bb47c3dff4ef6f43d2beee7f784047c1ba1c37344f1eb9b6312276a5b

[root@docker mysql_data]# docker exec -it db2a557 /bin/bash

root@db2a557bb47c:/# mysql -uroot -p 
Enter password: 
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

mysql> create database shy charset utf8mb4;
Query OK, 1 row affected (0.00 sec)

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| shy                |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql> exit
Bye
root@db2a557bb47c:/# exit
exit


[root@docker mysql_data]# ls   # 发现刚新创的数据库文件

# 重新挂载验证是否有刚刚新创的库
[root@docker mysql_data]# docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD="123456" -v /opt/mysql_data/:/var/lib/mysql c20987f18b13

[root@docker mysql_data]# docker exec -it 1e13f80 /bin/bash
root@1e13f807e359:/# mysql -uroot -p123456 -e "show databases"   # 没有影响，新创的库还在；证明没有初始化
```

```shell
# 杀死容器
	docker kill container_name   # ps查看的任务码非0，非0是不正常退出，程序内部错误
# 查看容器列表
    docker ps
	docker ps –a 
```

### 导入导出镜像

```shell
# 导出
# 格式：docker save [OPTIONS] IMAGE [IMAGE...]
OPTIONS：可选参数
IMAGE：镜像
OPTIONS的常用值
-o string: 指定目标文件，和linux原生命令>有相同作用

# docker save 镜像id/镜像名 > /opt/alpine.tar   用镜像id导出来的是废镜像<none>
# docker save -o /opt/alpine.tar 镜像名 

# 导出镜像
	docker save -o 否则导入镜像没有镜像标签以及名字 
	例子：docker image save centos > docker-centos7.4.tar.gz
#导入镜像
	docker load  例子：docker image load -i docker-centos7.4.tar.gz
# load命令可以从指定文件中加载镜像，该文件需要是save命令保存的文件
```

```shell
# 将alpine镜像打包成alpine.tar
[root@docker ~]# docker images
REPOSITORY   TAG             IMAGE ID       CREATED        SIZE
nginx        latest          605c77e624dd   4 months ago   141MB
mysql        5.7             c20987f18b13   5 months ago   448MB
alpine       latest          c059bfaa849c   5 months ago   5.59MB
nginx        stable-alpine   373f8d4d4c60   6 months ago   23.2MB
ubuntu       latest          ba6acccedd29   7 months ago   72.8MB
centos       7               eeb6ee3f44bd   8 months ago   204MB

[root@docker ~]# docker save c059bfaa849c > /opt/alpine.tar   # 没有使用-o指定名字导出来的是废镜像


# 导入
# docker load < 文件来源 或者 docker load -i 文件来源

[root@docker ~]# docker rmi c059bfaa849c
[root@docker ~]# docker load < /opt/alpine.tar 
8d3ac3489996: Loading layer [==================================================>]  5.866MB/5.866MB
Loaded image ID: sha256:c059bfaa849c4d8e4aecaeb3a10c2d9b3d85f5165c66ad3a4d937758128c4d18
[root@docker ~]# docker images
REPOSITORY   TAG             IMAGE ID       CREATED        SIZE
nginx        latest          605c77e624dd   4 months ago   141MB
mysql        5.7             c20987f18b13   5 months ago   448MB
<none>       <none>          c059bfaa849c   5 months ago   5.59MB    # 没有指定名字识别不出来，是废镜像
nginx        stable-alpine   373f8d4d4c60   6 months ago   23.2MB
ubuntu       latest          ba6acccedd29   7 months ago   72.8MB
centos       7               eeb6ee3f44bd   8 months ago   204MB
[root@docker ~]# docker rmi c059bfaa849c
Deleted: sha256:c059bfaa849c4d8e4aecaeb3a10c2d9b3d85f5165c66ad3a4d937758128c4d18
Deleted: sha256:8d3ac3489996423f53d6087c81180006263b79f206d3fdec9e66f0e27ceb8759
[root@docker ~]# docker load -i /opt/alpine.tar


# 正确导出与导入一
[root@docker ~]# docker save -o /opt/alpine.tar alpine:latest
[root@docker ~]# docker rmi c059bfaa849c
[root@docker ~]# docker load -i /opt/alpine.tar
```



### 导入导出容器

```shell
#export：将容器打包成一个文件
#export命令可以将容器打包到一个文件中，它和save命令比较容易混淆
#export和save的不同之处在于：export打包的是容器，save打包的是镜像
#export打包的是容器当时的快照，至于容器的历史记录和元数据信息都会丢失。还有，export的文件在被import成一个镜像时，可以重新指定镜像的名称和版本号


#格式：docker export [OPTIONS] CONTAINER
OPTIONS：可选参数
CONTAINER：容器
OPTIONS的常用值
-o string: 指定打包文件
export常用写法
将my-boot容器打包到my-boot.tar文件



# 由容器导出镜像：
        docker export -o 名字.tar.gz 容器名字/id
        docker import 名字.tar.gz 另外命名  （注意export模式会把默认命令取消掉。启动时要指定默认命令）
#        例如：
        docker run -d -p80:80 4ce44d891b27 /docker-entrypoint.sh nginx -g 'daemon off;'
        
# import可以从本地文件或远程文件中导入镜像到本地仓库；如果是从文件中导入，这个文件需要是export命令导出的文件
```

```shell
[root@docker ~]# docker rm -f `docker ps -a -q`
4250861b2dd5
1e13f807e359
[root@docker ~]# docker run -d -p 80:80 373f8d4d4c60
c5061caffa08793ae6b3afcb69c6032b4ffdce47c319fa3ab73ebeb7a5f54ccb
[root@docker ~]# docker ps

[root@docker ~]# docker exec -it c5061caffa08 /bin/sh
/ # vi /usr/share/nginx/html/index.html
# 更改如下
This is 70
/ # exit

[root@docker ~]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS                               NAMES
c5061caffa08   373f8d4d4c60   "/docker-entrypoint.…"   4 minutes ago   Up 4 minutes   0.0.0.0:80->80/tcp, :::80->80/tcp   relaxed_wescoff

[root@docker ~]# docker export -o /opt/seven.tar.gz c5061caffa08   # 导出


# 导入并启动
# 可以直接创建导入，也可以重新打标签和备注
# 从/opt/seven.tar.gz文件创建镜像，并指定镜像名称为seven、版本号为v1
[root@docker ~]# docker import /opt/seven.tar.gz seven:v1
sha256:b95540f0c1470c5969c64f4e842d477849d98141f5774aede97f943e97c51f83
[root@docker ~]# docker images
REPOSITORY   TAG             IMAGE ID       CREATED          SIZE
seven        v1              b95540f0c147   14 seconds ago   22.9MB
nginx        latest          605c77e624dd   4 months ago     141MB
mysql        5.7             c20987f18b13   5 months ago     448MB
alpine       latest          c059bfaa849c   5 months ago     5.59MB
nginx        stable-alpine   373f8d4d4c60   6 months ago     23.2MB
ubuntu       latest          ba6acccedd29   7 months ago     72.8MB
centos       7               eeb6ee3f44bd   8 months ago     204MB

# 启动，因为容器所有元信息都没有，所以启动需要/docker-entrypoint.sh nginx -g 'daemon off;'

[root@docker ~]# docker run -d -p 90:80 b95540f0c147 /docker-entrypoint.sh nginx -g 'daemon off;'
b1d6af7610591327697f23fc5771fa153ed9ce8508bf47921246c313e3841eb4
[root@docker ~]# docker ps
# 浏览器打开90
```

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205211233043.png)



<font color='red'>**镜像与容器的导入导出总结**</font>

1. **save命令打包的是镜像，包含镜像的所有信息**
2. **exprot命令打包的是容器，只是保存容器当时的快照，历史记录和元数据信息将会丢失**
3. **export和save的不同之处在于：export打包的是容器，save打包的是镜像**
4. **保存镜像（保存镜像载入后获得跟原镜像id相同的镜像）**
5. **保存容器（保存容器载入后获得跟原镜像id不同的镜像）**







### Dockerfile

Dockerfile 是一个文本文件，其内包含了一条条的 **指令(Instruction)**，每一条指令构建一层，因此每一条指令的内容，就是描述该层应当如何构建。

```shell
1、FROM
格式：FROM <image>或 FROM <image>:<tag>
基础镜像来源，必须在第一行指令中指定，不指定标记则默认为latest。

2、LABEL
格式：LABEL <name>=<value>
指定添加元数据到镜像，可指定多个标签信息。

3、RUN
格式：RUN <command>
每条指令将在当前镜像基础上执行，并提交为新的镜像。

4、CMD
格式：CMD <command>
指定启动容器时执行的命令，每个Dockerfile只能有一条CMD指令，如果指定了多条CMD指令，则只会执行最后一条CMD指令。如果在启动镜像时指定了启动指令，则镜像预设的CMD指令不执行。一般用于执行容器时提供默认值。

5、EXPOSE
格式：EXPOSE <port>
指定镜像启动后暴露的端口，在容器启动时需要通过 -p 做端口映射

6、ENV
格式：ENV <key> <value>
指定环境变量，使用在构建阶段中的所有后续指令的环境。

7、ADD
格式：ADD  <src> <dest>
该指令会在<src>(本地文件系统或远程网络位置) 进行复制新文件，并将它们添加到容 路径上的文件系统中<dest>。

8、COPY
格式：COPY <src> <dest>
复制本地主机的 <src> (为 Dockerfile 所在目录的相对路径) 到容器中的 <dest>。

9、ENTRYPOINT
格式：ENTRYPOINT <command>
配置容器启动后执行的命令，并且不可被docker run提供的参数覆盖。如果指定了多条ENTRYPOINT指令，则只会执行最后一条ENTRYPOINT指令。

10、VOLUME
格式：VOLUME  <FileSystemMountPoint>
创建一个可以从本地主机或其他容器挂载的挂载点，一般用来存放数据库和需要保持的数据等

11、USER
格式：USER <user>:<group> | USER <uid>:<gid>
指定运行容器时的用户名或 UID，后续的 RUN 也会使用指定用户。

12、WORKDIR
格式：WORKDIR <FileSystemPath>
为后续的 COPY、ADD、RUN、CMD、ENTRYPOINT 指令配置工作目录。（可以使用多个 WORKDIR 指令，后续命令如果参数是相对路径， 则会基于之前命令指定的路径）

13、ARG
格式：ARG <varname>[=<value>]
该ARG指令定义了一个变量，用户可以docker build使用该--build-arg <varname>=<value> 标志在构建时将该变量传递给构建器。

14、ONBUILD 
格式：ONBUILD [INSTRUCTION]
配置当所创建的镜像作为其它新创建镜像的基础镜像时，所执行的操作指令，就好像它已经FROM在下游指令之后立即插入一样 Dockerfile。

15、STOPSIGNAL
格式：STOPSIGNAL <signal>
设置将发送到容器的系统调用信号以退出。此信号可以是与内核的系统调用表中的位置匹配的有效无符号数，例如9，或SIGNAME格式的信号名，例如SIGKILL。

16、HEALTHCHECK heathcheck
格式：HEALTHCHECK [OPTIONS] CMD command
测试容器以检查它是否仍在工作。即使服务器进程仍在运行，这也可以检测到陷入无限循环且无法处理新连接的Web服务器等情况。当容器指定了运行状况检查时，除了正常状态外，它还具有运行状况。这个状态最初是starting。每当健康检查通过时，它就会变成healthy（以前所处的状态）。经过一定数量的连续失败后，它就变成了unhealthy。

17、SHELL
格式：SHELL ["executable", "parameters"]
该SHELL指令允许覆盖用于shell命令形式的默认shell。Linux上的默认shell是["/bin/sh", "-c"]，而在Windows上["cmd", "/S", "/C"]。该SHELL指令必须以JSON格式写入Dockerfile。
```

#### 总结

```shell
FROM 开头必须是FROM注意一定是大写。后面跟镜像名字或者空（特殊写法）
MAINTAINER 声明作者是谁，可以省略。
ENV 声明环境变量，往镜像里注入需要的环境变量
COPY/ADD 都是把本地文件或者目录加入到镜像内，其中COPY可以覆盖文件，ADD与COPY区别在于有解压包的作用。
WORKDIR 声明工作目录在哪。构建镜像时会在容器内改目录一直操作，直到下一个WORKDIR出现或者RUN中出现cd命令。
RUN 执行主要命令和安装过程的关键字。注意RUN写的次数越少，镜像层就越少，建议所有操作只写一个RUN

dockerfile支持变量用，定义与引用与shell脚本相同

EXPOSE 暴露容器运行时默认的端口。
ENTRYPOINT/CMD 容器运行时默认运行的命令也就是pid 1进程命令。此命令在docker中要求必须hold住，容器才可以正常运行。这俩参数都可以生产pid 1运行命令，但是有区别，当两个关键字都存在时。ENTRYPOINT级别高于CMD，CMD运行内容会默认变成ENTRYPOINT的运行内容参数。从而两个参数形成一条运行命令。
```



#### centos-redis

```shell
[root@docker ~]# mkdir -p /docker/redis
[root@docker ~]# cd /docker/redis/
[root@docker redis]# wget http://download.redis.io/releases/redis-5.0.8.tar.gz
[root@docker redis]# ls
redis-5.0.8.tar.gz
[root@docker redis]# vim Dockerfile
FROM centos:7
WORKDIR /data
ADD redis-5.0.8.tar.gz /data
RUN yum install gcc gcc-c++ make -y && cd redis-5.0.8 && make && make install
EXPOSE 6379
CMD ["/data/redis-5.0.8/src/redis-server"]

[root@docker redis]# docker build -t redis:v1 .



# 验证
[root@docker redis]# docker images
REPOSITORY       TAG             IMAGE ID       CREATED         SIZE
redis            v1              9a8285dd6298   5 seconds ago   625MB

[root@docker redis]# docker run -d 9a8285dd6298
9eb3bcb1dacda4494aaa8d396bfc7a885ba6beda192cc6cf7a0b6937422a8633
[root@docker redis]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS      NAMES
9eb3bcb1dacd   9a8285dd6298   "/data/redis-5.0.8/s…"   5 seconds ago   Up 5 seconds   6379/tcp   naughty_rubin

[root@docker redis]# docker exec -it 9eb3bcb1dacd bash
[root@9eb3bcb1dacd data]# ls
redis-5.0.8

[root@9eb3bcb1dacd data]# ps -ef | grep redis
root          1      0  0 14:05 ?        00:00:00 /data/redis-5.0.8/src/redis-server *:6379
root         28     10  0 14:06 pts/0    00:00:00 grep --color=auto redis

[root@9eb3bcb1dacd data]# redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> exit
```

#### 不同启动方式，调用容器启动的第一个命令是不同的

```
[root@docker1 redis]# docker start 651cace10140
651cace10140
[root@docker1 redis]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
651cace10140        1fe9fbc1d6f5        "/bin/bash"         3 minutes ago       Up 2 seconds        6379/tcp            focused_allen


[root@docker1 redis]# docker run -d 1fe9fbc1d6f5 
15210e98c9ddb6098b815882e98606bc3607376899183d2612a131149f1889a4
[root@docker1 redis]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
15210e98c9dd        1fe9fbc1d6f5        "/data/redis-5.0.8/s…"   6 seconds ago       Up 5 seconds        6379/tcp            dreamy_borg

```







```shell
# 优化一
[root@docker redis]# vim Dockerfile
FROM centos:7
WORKDIR /data
ADD redis-5.0.8.tar.gz /data
RUN yum install gcc gcc-c++ make -y && cd redis-5.0.8 && make && make install \
    && cp /data/redis-5.0.8/src/redis-server /usr/local/bin && cp /data/redis-5.0.8/src/redis-cli /usr/local/bin \
    && cp /data/redis-5.0.8/redis.conf /etc/ && rm -rf /data/* && yum remove gcc gcc-c++ make -y && yum clean all
EXPOSE 6379
CMD ["redis-server"]


[root@docker redis]# docker build -t redis:v2 .
[root@docker redis]# docker images    # 可以看出v2经过优化比原来少了一半左右
REPOSITORY                                           TAG             IMAGE ID       CREATED          SIZE
redis                                                v2              18680627f22d   12 seconds ago   326MB
redis                                                v1              9a8285dd6298   20 minutes ago   625MB

# 验证
[root@docker redis]# docker run -d 18680627f22d
5a9d56c1caf2dee01c7070bd00904db47ec9281c45e5896db201e489798d71be
[root@docker redis]# docker ps
[root@docker redis]# docker exec -it 5a9d56c1caf2 bash
[root@5a9d56c1caf2 data]# redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> exit
```

#### ubuntu_redis

```shell
[root@docker redis]# cp Dockerfile Dockerfile.bak
[root@docker redis]# vim Dockerfile
FROM ubuntu
WORKDIR /data
ADD redis-5.0.8.tar.gz /data
RUN sed  -i 's#archive.ubuntu.com#mirrors.aliyun.com#g' /etc/apt/sources.list && apt-get update \ 
    && apt-get install gcc  make -y && cd redis-5.0.8 && make && make install \
    && cp /data/redis-5.0.8/src/redis-server /usr/local/bin && cp /data/redis-5.0.8/src/redis-cli /usr/local/bin \
    && cp /data/redis-5.0.8/redis.conf /etc/
EXPOSE 6379
CMD ["redis-server"]

[root@docker redis]# docker build -t redis-ubuntu:v1 .

# 验证
[root@docker redis]# docker images
REPOSITORY                                           TAG             IMAGE ID       CREATED          SIZE
redis-ubuntu                                         v1              65ba35d38b5e   4 seconds ago    466MB

[root@docker redis]# docker ps   # 一般5s后不消亡都是成功的
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS      NAMES
de51550497e9   65ba35d38b5e   "redis-server"           11 seconds ago   Up 10 seconds   6379/tcp   dreamy_lewin

```



```shell
# 优化一
[root@docker redis]# vim Dockerfile
FROM ubuntu
WORKDIR /data
ADD redis-5.0.8.tar.gz /data
RUN sed  -i 's#archive.ubuntu.com#mirrors.aliyun.com#g' /etc/apt/sources.list && apt-get update \
    && apt-get install gcc  make -y && cd redis-5.0.8 && make && make install \
    && cp /data/redis-5.0.8/src/redis-server /usr/local/bin && cp /data/redis-5.0.8/src/redis-cli /usr/local/bin \
    && cp /data/redis-5.0.8/redis.conf /etc/ && rm -rf /data/* && apt-get remove gcc make -y && apt clean
EXPOSE 6379
CMD ["redis-server"]

[root@docker redis]# docker build -t redis-ubuntu:v2 .

# 验证
[root@docker redis]# docker images   # 可以看出v2经过优化比原来少了一半左右
REPOSITORY                                                  TAG             IMAGE ID       CREATED          SIZE
redis-ubuntu                                                v2              00880168900a   5 seconds ago    320MB
redis-ubuntu                                                v1              65ba35d38b5e   18 minutes ago   466MB

[root@docker redis]# docker ps 
CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS      NAMES
99584cdb6957   00880168900a   "redis-server"           About a minute ago   Up About a minute   6379/tcp   cool_davinci
```



```shell
# 优化三  多阶段构建(可以不用别名用数字代替层数，也可以设置别名AS)

[root@docker redis]# vim Dockerfile
FROM ubuntu AS base
WORKDIR /data
ADD redis-5.0.8.tar.gz /data
RUN sed  -i 's#archive.ubuntu.com#mirrors.aliyun.com#g' /etc/apt/sources.list && apt-get update \
    && apt-get install gcc  make -y && cd redis-5.0.8 && make && make install

FROM ubuntu
COPY --from=base /data/redis-5.0.8/src/redis-server /usr/local/bin/
COPY --from=base /data/redis-5.0.8/src/redis-cli /usr/local/bin/
COPY --from=base /data/redis-5.0.8/redis.conf /etc/
EXPOSE 6379
CMD ["redis-server"]

[root@docker redis]# docker build -t redis-ubuntu:v3 .

# 验证
[root@docker redis]# docker images
REPOSITORY                                                  TAG             IMAGE ID       CREATED             SIZE
redis-ubuntu                                                v3              0c6f5f472e5a   3 minutes ago       90.8MB

[root@docker redis]# docker run -d 0c6f5f472e5a
24c64bd380f2c10b777515f322ddc488f59a375586f9cf6d1c30d756d90055de
[root@docker redis]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED             STATUS             PORTS      NAMES
24c64bd380f2   0c6f5f472e5a   "redis-server"           8 minutes ago       Up 8 minutes       6379/tcp   magical_spence
```



#### nginx-redis

```shell
[root@docker ~]# mkdir /docker/nginx-redis
[root@docker ~]# cd /docker/nginx-redis/
[root@docker nginx-redis]# ls
nginx-1.20.2.tar.gz  redis-5.0.8.tar.gz
[root@docker nginx-redis]# tar xf redis-5.0.8.tar.gz && cd redis-5.0.8
[root@docker redis-5.0.8]# sed -i "s/daemonize no/daemonize yes/g" redis.conf && cp redis.conf ../

[root@docker nginx-redis]# vim run.sh
[root@docker nginx-redis]# pwd
/docker/nginx-redis
[root@docker nginx-redis]# vim run.sh 
#!/bin/sh
echo "start nginx"
nginx
echo "start redis"
redis-server /etc/redis.conf
tail -f /dev/null


[root@docker nginx-redis]# vim Dockerfile
FROM centos:7
WORKDIR /data
ADD redis-5.0.8.tar.gz /data
ADD nginx-1.20.2.tar.gz /data
COPY redis.conf /etc/redis.conf
COPY run.sh /run.sh
RUN yum install gcc gcc-c++ make prce-devel openssl-devel -y && chmod a+x /run.sh \
    && cd redis-5.0.8 && make && make install \
    && cp /data/redis-5.0.8/src/redis-server /usr/local/bin && cp /data/redis-5.0.8/src/redis-cli /usr/local/bin \
    && cd /data/nginx-1.20.2 && useradd www -s /sbin/nologin \
    && CONFIG="\
       --prefix=/usr/local/nginx \
       --with-http_stub_status_module \
       --with-http_v2_module \
       --with-http_ssl_module  \
       --with-http_gzip_static_module \
       --with-http_realip_module  \
       --with-http_flv_module \
       --with-stream \
       --sbin-path=/usr/sbin/nginx \
       --modules-path=/usr/lib/nginx/modules \
       --conf-path=/usr/local/nginx/conf/nginx.conf \
       --user=www \
       --group=www \
      " \
    && ./configure $CONFIG && make && make install \
    && rm -rf /data/* && yum remove gcc gcc-c++ make -y && yum clean all
EXPOSE 6379
EXPOSE 80
ENTRYPOINT ["/bin/sh","-c"]
CMD ["/run.sh"]


[root@docker nginx-redis]# docker build -t nginx-redis:nr-v1 .

[root@docker nginx-redis]# docker images
REPOSITORY                                                  TAG       IMAGE ID       CREATED              SIZE
nginx-redis                                                 nr-v1     0a044c0707b0   About a minute ago   349MB

[root@docker nginx-redis]# docker run -d 0a044c0707b0
5e915a45e4c8b0dd115f8f4a8dd10a6ad1ae9a92e6bd0b06ca7abcd4da075d6c
[root@docker nginx-redis]# docker ps
CONTAINER ID   IMAGE          COMMAND                CREATED          STATUS          PORTS              NAMES
5e915a45e4c8   0a044c0707b0   "/bin/sh -c /run.sh"   5 seconds ago    Up 5 seconds    80/tcp, 6379/tcp   silly_germain

[root@docker nginx-redis]# docker exec -it 5e915a45e4c8 bash
[root@5e915a45e4c8 data]# ps -ef          
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 17:14 ?        00:00:00 /bin/sh /run.sh
root          7      1  0 17:14 ?        00:00:00 nginx: master process nginx
www           9      7  0 17:14 ?        00:00:00 nginx: worker process
root         10      1  0 17:14 ?        00:00:00 redis-server 127.0.0.1:6379
root         14      1  0 17:14 ?        00:00:00 tail -f /dev/null
root         15      0  0 17:14 pts/0    00:00:00 bash
root         33     15  0 17:15 pts/0    00:00:00 ps -ef
```



```shell
# 优化

[root@docker nginx-redis]# vim Dockerfile
FROM centos:7
WORKDIR /data
ADD redis-5.0.8.tar.gz /data
ADD nginx-1.20.2.tar.gz /data
RUN yum install gcc gcc-c++ make prce-devel openssl-devel -y \
    && cd redis-5.0.8 && make && make install \
    && cd /data/nginx-1.20.2 && useradd www -s /sbin/nologin \
    && CONFIG="\
       --prefix=/usr/local/nginx \
       --with-http_stub_status_module \
       --with-http_v2_module \
       --with-http_ssl_module  \
       --with-http_gzip_static_module \
       --with-http_realip_module  \
       --with-http_flv_module \
       --with-stream \
       --sbin-path=/usr/sbin/nginx \
       --modules-path=/usr/lib/nginx/modules \
       --conf-path=/usr/local/nginx/conf/nginx.conf \
       --user=www \
       --group=www \
      " \
    && ./configure $CONFIG && make && make install 
FROM centos:7
COPY redis.conf /etc/redis.conf
COPY run.sh /run.sh
COPY --from=0 /data/redis-5.0.8/src/redis-server /usr/local/bin/
COPY --from=0 /data/redis-5.0.8/src/redis-cli /usr/local/bin/
COPY --from=0 /data/redis-5.0.8/redis.conf /etc/
COPY --from=0 /usr/local/nginx /usr/local/nginx
COPY --from=0 /usr/sbin/nginx /usr/sbin/
COPY --from=0 /lib64 /lib64
RUN useradd www -s /sbin/nologin && chmod a+x /run.sh
EXPOSE 6379
EXPOSE 80
ENTRYPOINT ["/bin/sh","-c"]
CMD ["/run.sh"]


[root@docker nginx-redis]# docker build -t nginx-redis:nr-v2 .

[root@docker nginx-redis]# docker images
REPOSITORY                                                  TAG       IMAGE ID       CREATED             SIZE
nginx-redis                                                 nr-v2     79991815f3f0   42 seconds ago      306MB


[root@docker nginx-redis]# docker run -d 79991815f3f0
529d0163efdabc56db95195da1e90f2e5667d57bf0c121c1b07fc914cb100913
[root@docker nginx-redis]# docker ps
CONTAINER ID   IMAGE          COMMAND                CREATED          STATUS          PORTS              NAMES
529d0163efda   79991815f3f0   "/bin/sh -c /run.sh"   38 seconds ago   Up 37 seconds   80/tcp, 6379/tcp   laughing_mayer
[root@docker nginx-redis]# docker exec -it 529d0163efda bash
[root@529d0163efda /]# ps -ef
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 17:56 ?        00:00:00 /bin/sh /run.sh
root          8      1  0 17:56 ?        00:00:00 nginx: master process nginx
root          9      1  0 17:56 ?        00:00:00 redis-server 127.0.0.1:6379
www          10      8  0 17:56 ?        00:00:00 nginx: worker process
root         14      0  0 17:56 pts/0    00:00:00 bash
root         28     14  0 17:56 pts/0    00:00:00 ps -ef
```



```shell
# 写法二
[root@docker nginx-redis]# vim Dockerfile 
FROM centos:7
WORKDIR /data
ADD redis-5.0.8.tar.gz /data
ADD nginx-1.20.2.tar.gz /data
RUN yum install gcc gcc-c++ make prce-devel openssl-devel -y \
    && cd redis-5.0.8 && make && make install \
    && cd /data/nginx-1.20.2 && useradd www -s /sbin/nologin \
    && CONFIG="\
       --prefix=/usr/local/nginx \
       --with-http_stub_status_module \
       --with-http_v2_module \
       --with-http_ssl_module  \
       --with-http_gzip_static_module \
       --with-http_realip_module  \
       --with-http_flv_module \
       --with-stream \
       --sbin-path=/usr/sbin/nginx \
       --modules-path=/usr/lib/nginx/modules \
       --conf-path=/usr/local/nginx/conf/nginx.conf \
       --user=www \
       --group=www \
      " \
    && ./configure $CONFIG && make && make install 
FROM centos:7
COPY run.sh /run.sh
COPY --from=0 /data/redis-5.0.8/src/redis-server /usr/local/bin/
COPY --from=0 /data/redis-5.0.8/src/redis-cli /usr/local/bin/
COPY --from=0 /data/redis-5.0.8/redis.conf /etc/
COPY --from=0 /usr/local/nginx /usr/local/nginx
COPY --from=0 /usr/sbin/nginx /usr/sbin/
COPY --from=0 /lib64 /lib64
RUN useradd www -s /sbin/nologin && chmod a+x /run.sh  && sed -i "s/daemonize no/daemonize yes/g" /etc/redis.conf
EXPOSE 6379
EXPOSE 80
ENTRYPOINT ["/bin/sh","-c"]
CMD ["/run.sh"]



[root@docker nginx-redis]# docker build -t nginx-redis:nr-v3 .

[root@docker nginx-redis]# docker images
REPOSITORY                                                  TAG       IMAGE ID       CREATED          SIZE
nginx-redis                                                 nr-v3     48b050033b9d   9 seconds ago    306MB

[root@docker nginx-redis]# docker run -d 48b050033b9d
dea9e5ef0b8ac70a52aa157f16eafaef35edd880546b69e8528c553bd8256c10
[root@docker nginx-redis]# docker ps
CONTAINER ID   IMAGE          COMMAND                CREATED          STATUS          PORTS              NAMES
dea9e5ef0b8a   48b050033b9d   "/bin/sh -c /run.sh"   53 seconds ago   Up 53 seconds   80/tcp, 6379/tcp   loving_lovelace
```



#### 自写mysql镜像

```shell
[root@docker ~]# mkdir /docker/lnmp
[root@docker ~]# cd !$
[root@docker lnmp]# ls
mysql-5.7.30-linux-glibc2.12-x86_64.tar.gz  

[root@docker lnmp]# vim Dockerfile
FROM centos:7
WORKDIR /usr/local/
COPY my.cnf /etc/my.cnf
COPY run.sh /run.sh
ADD mysql-5.7.30-linux-glibc2.12-x86_64.tar.gz /usr/local/
RUN yum install -y libaio-devel numactl-devel && yum clean all \
    && mv mysql-5.7.30-linux-glibc2.12-x86_64 mysql \
    && useradd mysql -s /sbin/nologin \
    && mkdir -p /data/mysql \
    && mkdir -p /var/log/mysql \
    && mkdir -p /data/binlog/ \
    && chmod o+w /data/ \
    && chown mysql:mysql -R /usr/local/mysql /data/mysql /var/log/mysql /data/binlog/ /etc/my.cnf \
    && echo 'export PATH=$PATH:/usr/local/mysql/bin' >> /etc/profile \
    && source /etc/profile \
    && echo 'source /etc/profile'>> /root/.bashrc \
    && chmod a+x /run.sh
EXPOSE 3306
ENTRYPOINT ["/bin/sh","-c"]
CMD ["/run.sh"] 

[root@docker lnmp]# cat my.cnf 
[mysqld]
user=mysql 
basedir=/usr/local/mysql        
datadir=/data/mysql             
server_id=1                         
port=3306                           
socket=/data/mysql/mysql.sock
log_bin=/data/binlog/mysql-bin
sync_binlog=1
binlog_format=row
        

[mysql]         
socket=/data/mysql/mysql.sock 

[mysqld_safe]
log-error=/var/log/mysql/mysql.log      
pid-file=/data/mysql/mysql.pid


[root@docker lnmp]# cat run.sh 
#!/bin/sh
#/usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf --user=mysql
#/usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql
/usr/local/mysql/bin/mysqld --initialize-insecure  --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql
/usr/local/mysql/support-files/mysql.server start

tail -f /dev/null


[root@docker lnmp]# docker build -t mysql:v1 .
```



## 复习

1、创建容器

```bash
docker run [参数] [镜像名称|ID] [CMD]

-d : 以守护进程运行
-e : 定义一个容器内部的环境变量
-i ：打开标准输出
-t : 创建一个终端
-v : 挂载一个本地目录/文件到容器内部
--name : 指定容器的名称，将名称解析到Docker DNS 上
-P: 随机映射一个端口
-p ：指定一个端口
--rm : 当容器的生命周期结束的时候立即自动删除容器
--link : 连接一个容器，单向链接
--restart=always 需要开机自启容器
--network
```

2、启动容器

```bash
docker start 容器名称|ID
```

3、停止容器

```bash
docker stop 容器名称|ID
```

4、查看容器列表

```bash
docker ps
-a : 查看所有的容器
-q : 仅查看容器ID
```

5、删除容器

```bash
docker rm [容器ID|名称]

-f : 强制删除

docker rm -f $(docker ps -a -q)
```

6、复制

```bash
# 由宿主主机复制到容器内部
docker cp [宿主主机路径]   [容器ID]:[容器内部的路径]

# 由容器内部复制到宿主主机
docker cp [容器ID]:[容器内部的路径] [宿主主机路径]   
```

7、进入容器

```bash
# exec : exec的设计目的实际上是在宿主主机外执行一个容器内部的命令
docker exec -it  [容器的ID|名称] [cmd]

# attach ： 连接上容器内部PID=1的进程

# nsenter ： 宿主主机的命令，

# ssh ： 
```



## 数据卷

据卷的本质其实依然是宿主操作系统上的一个目录，只不过这个目录存放在 Docker 内部，接受 Docker 的管理。

数据卷是一个可供一个或多个容器使用的特殊目录，它绕过 UFS，可以提供很多有用的特性：

- 数据卷 可以在容器之间共享和重用
- 对 数据卷 的修改会立马生效
- 对 数据卷 的更新，不会影响镜像
- 数据卷 默认会一直存在，即使容器被删除



```shell
[root@docker ~]# ls /   # 刚开始没有data目录
bin  boot  dev  docker  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

[root@docker ~]# docker run -d -v /data/web:/usr/share/nginx/html 605c77e624dd   # 选择挂载
7eb2ca32105517d58a5d012ce34366d9484ac974db42be2c7b24902e8acb1a44

[root@docker ~]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS     NAMES
7eb2ca321055   605c77e624dd   "/docker-entrypoint.…"   3 seconds ago   Up 2 seconds   80/tcp    suspicious_volhard

[root@docker ~]# ls /   # 可以看出尽管没有data目录，加了-v会自动创建
bin  boot  data  dev  docker  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
```



### 查看数据卷

```shell
[root@docker ~]# docker volume ls
DRIVER              VOLUME NAME
local               c608e204441ddf9e2d8bb66b655abde7f3ec44331d57947d965f1b5f1865e3d5
[root@docker1 volumes]# ll /var/lib/docker/volumes
总用量 24
drwxr-xr-x 3 root root    19 11月  7 17:13 c608e204441ddf9e2d8bb66b655abde7f3ec44331d57947d965f1b5f1865e3d5
-rw------- 1 root root 32768 11月  9 09:20 metadata.db

```



**测试**

当没有写明宿主机文件路径，会在哪里创建目录

```shell
[root@docker ~]# docker run -d -v uplooking:/usr/share/nginx/html 605c77e624dd
7c3611d9b12a47f5bf240ec024e3f0703eb4eae66e5f9abbd18ef124af40c17b

[root@docker ~]# docker volume ls   # 当不指定路径的时候就会生成一个卷
DRIVER    VOLUME NAME
local     uplooking

[root@docker ~]# docker volume inspect uplooking   # 查看卷的信息
[
    {
        "CreatedAt": "2022-05-28T23:05:16+08:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/uplooking/_data", #可以看到创建在这里，去到里面会发现nginx的一些文件也在里面
        "Name": "uplooking",
        "Options": null,
        "Scope": "local"
    }
]
```



### 创建卷

```shell
[root@docker ~]# docker volume create shy
shy
[root@docker ~]# docker volume create ls
ls
[root@docker ~]# docker volume ls
DRIVER    VOLUME NAME
local     ls
local     shy
local     uplooking


# 使用卷
[root@docker ~]# docker run -d -v ls:/usr/share/nginx/html 605c77e624dd
831316f118989ecb38e3bdaf9cb4a3fa4607b617f70331b7335e240091f6039d

[root@docker ~]# ll /var/lib/docker/volumes/ls/_data/   # 换了卷照样会在里面生成文件
50x.html    index.html
```



### 删除卷

```shell
# 正在使用的卷是不允许删除的
# docker volume rm 名字|ID

[root@docker ~]# docker volume rm shy
shy

```



**docker[修改存储位置](https://www.jianshu.com/p/06cb1b264c44)**

**如果需要在删除容器的同时移除数据卷。可以在删除容器的时候使用 `docker rm -v` 这个命令。**







## **网络配置**

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205282332669.png)



### bridge模式（默认）

1. 当Docker进程启动时，会在主机上创建一个名为docker0的虚拟网桥，此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似，这样主机上的所有容器就通过交换机连在了一个二层网络中。
2. 从docker0子网中分配一个IP给容器使用，并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备，Docker将veth pair设备的一端放在新创建的容器中，并命名为eth0（容器的网卡），另一端放在主机中，以vethxxx这样类似的名字命名，并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看。
3. bridge模式是docker的默认网络模式，不写--net参数，就是bridge模式。使用docker run -p时，docker实际是在iptables做了DNAT规则，实现端口转发功能。可以使用iptables -t nat -vnL查看。

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205290856636.png)



### host模式

- 众所周知，Docker使用了Linux的Namespaces技术来进行资源隔离，如PID Namespace隔离进程，Mount Namespace隔离文件系统，Network Namespace隔离网络等。一个Network Namespace提供了一份独立的网络环境，包括网卡、路由、Iptable规则等都与其他的Network Namespace隔离。一个Docker容器一般会分配一个独立的Network Namespace。但如果启动容器的时候使用host模式，那么这个容器将不会获得一个独立的Network Namespace，而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡，配置自己的IP等，而是使用宿主机的IP和端口。
- 例如，我们在10.10.101.105/24的机器上用host模式启动一个含有web应用的Docker容器，监听tcp80端口。当我们在容器中执行任何类似ifconfig命令查看网络环境时，看到的都是宿主机上的信息。而外界访问容器中的应用，则直接使用10.10.101.105:80即可，不用任何NAT转换，就如直接跑在宿主机中一样。但是，容器的其他方面，如文件系统、进程列表等还是和宿主机隔离的。

```shell
[root@docker ~]# docker images
REPOSITORY                                            TAG              IMAGE ID       CREATED        SIZE
registry.cn-shenzhen.aliyuncs.com/xiaosu_shy/oldliu   nginx-php-74v3   38ec4b2456ca   2 weeks ago    564MB
nginx                                                 latest           605c77e624dd   5 months ago   141MB
mysql                                                 5.7              c20987f18b13   5 months ago   448MB
ubuntu                                                latest           ba6acccedd29   7 months ago   72.8MB
centos                                                7                eeb6ee3f44bd   8 months ago   204MB
```

```shell
# 使用host模式
[root@docker ~]# docker run -d --net=host 38ec4b2456ca
12217c0c6fb0411a763369ca7906ddd674ce75d5513154dc265593c122949ba3

# docker ps发现ports没有
[root@docker ~]# docker ps
CONTAINER ID   IMAGE          COMMAND                CREATED         STATUS         PORTS     NAMES
12217c0c6fb0   38ec4b2456ca   "/run.sh /bin/sh -c"   9 seconds ago   Up 8 seconds             silly_ardinghelli


# 浏览器直接输入宿主机的IP地址
```

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205290900867.png)

```shell
# 进入容器发现主机名没有变化而且目录变为根下
[root@docker ~]# docker exec -it 12217c0c6fb0 bash
[root@docker /]# yum install -y net-tools
[root@docker /]# ifconfig #可以看出容器内把宿主机的端口、网络等都映射进来；
坏处攻击这个容器的网络、端口其实就是攻击宿主机
```

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205290903194.png)

```shell
[root@docker ~]# docker ps
CONTAINER ID   IMAGE          COMMAND                CREATED         STATUS         PORTS     NAMES
12217c0c6fb0   38ec4b2456ca   "/run.sh /bin/sh -c"   7 minutes ago   Up 7 minutes             silly_ardinghelli

# 生产上不建议使用host模式
[root@docker ~]# docker inspect 12217c0c6fb0   # 发现host中IP地址是空的；因为用的是宿主机的


[root@docker ~]# docker rm -f 12217c0c6fb0
12217c0c6fb0
```

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205290907175.png)



### container模式

- 在理解了host模式后，这个模式也就好理解了。这个模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace，而不是和宿主机共享。新创建的容器不会创建自己的网卡，配置自己的IP，而是和一个指定的容器共享IP、端口范围等。同样，两个容器除了网络方面，其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。

```shell
[root@docker ~]# docker images
REPOSITORY                                            TAG              IMAGE ID       CREATED        SIZE
registry.cn-shenzhen.aliyuncs.com/xiaosu_shy/oldliu   nginx-php-74v3   38ec4b2456ca   2 weeks ago    564MB
nginx                                                 latest           605c77e624dd   5 months ago   141MB
mysql                                                 5.7              c20987f18b13   5 months ago   448MB
ubuntu                                                latest           ba6acccedd29   7 months ago   72.8MB
centos                                                7                eeb6ee3f44bd   8 months ago   204MB
```

```shell
[root@docker ~]# docker run -d --name web nginx
bb9b6b9238f356ad9888a0a4bf2ffdff113e83874fb39415e1d6ff356119f4b3

[root@docker ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS     NAMES
bb9b6b9238f3   nginx     "/docker-entrypoint.…"   7 seconds ago   Up 6 seconds   80/tcp    web

#格式：docker run -d --net=container:容器名或容器ID 镜像ID
[root@docker ~]# docker run -d --net=container:web 38ec4b2456ca   # 命名一个容器为web，采用container网络模式
8d730393288ecc660d6113a6810549c6bd1b65eee6c232649b99174d72d352c7

[root@docker ~]# docker ps   # 发现采用container网络模式的容器没有ports
CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS     NAMES
8d730393288e   38ec4b2456ca   "/run.sh /bin/sh -c"     2 seconds ago        Up 1 second                   epic_lichterman
bb9b6b9238f3   nginx          "/docker-entrypoint.…"   About a minute ago   Up About a minute   80/tcp    web
```

```shell
# 进入container网络模式的容器
[root@docker ~]# docker exec -it 8d730393288e bash   # 进去发现主机名并不是这个容器的id，而是另外一个容器的id
[root@bb9b6b9238f3 /]# 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.2	bb9b6b9238f3
# 具体看图
```

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205290920570.png)

```shell
[root@docker ~]# docker inspect 8d730393288e   # 详细信息里host也是无IP地址的
```

 ![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205290924545.png)



### none模式(了解)

- 这个模式和前两个不同。在这种模式下，Docker容器拥有自己的Network Namespace，但是，并不为Docker容器进行任何网络配置。也就是说，这个Docker容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。

```shell
[root@docker ~]# docker run -d --net=none 38ec4b2456ca
d5e9ec254eafc5c47cbad75de5e9fd8013597e62ae1ea9473d541821e4fcc9a3
[root@docker ~]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS          PORTS     NAMES
d5e9ec254eaf   38ec4b2456ca   "/run.sh /bin/sh -c"     4 seconds ago    Up 3 seconds              sad_mccarthy
8d730393288e   38ec4b2456ca   "/run.sh /bin/sh -c"     10 minutes ago   Up 10 minutes             epic_lichterman
bb9b6b9238f3   nginx          "/docker-entrypoint.…"   11 minutes ago   Up 11 minutes   80/tcp    web

[root@docker ~]# docker inspect d5e9ec254eaf

# 这种模式容器里只有一张网卡lo
```

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205290926663.png)



| 网络模式  | 区别                                   |      |
| --------- | -------------------------------------- | ---- |
| bridge    | 与宿主机共享网卡，会产生一张虚拟网卡   |      |
| host      | 直接与宿主机共用网卡，不会产生虚拟网卡 |      |
| container | 与其它容器共用网卡，也不会产生虚拟网卡 |      |
| none      | 需要手动配置网卡配置                   |      |





### 总结

**None：不为容器配置任何网络功能，--net=none**
**Container：与另一个运行中的容器共享Network Namespace，--net=container:containerID（K8S）**
**Host：与宿主机共享Network Namespace，--net=host**
**Bridge：Docker设计的NAT网络模型**





## Docker compose

`**Compose` 项目是 Docker 官方的开源项目，负责实现对 Docker 容器集群的快速编排。从功能上看，跟 `OpenStack` 中的 `Heat` 十分类似。**

**其代码目前在 https://github.com/docker/compose 上开源。**

**`Compose` 定位是 「定义和运行多个 Docker 容器的应用（Defining and running multi-container Docker applications）」，其前身是开源项目 Fig。**

**`Docker-Compose`将所管理的容器分为三层，分别是`工程（project），服务（service）以及容器（container）`。Docker-Compose运行目录下的所有文件（docker-compose.yml，extends文件或环境变量文件等）组成一个工程，若无特殊指定工程名即为当前目录名。一个工程当中可包含多个服务，每个服务中定义了容器运行的镜像，参数，依赖。一个服务当中可包括多个容器实例，Docker-Compose并没有解决负载均衡的问题，因此需要借助其它工具实现服务发现及负载均衡。**

**Docker-Compose的工程配置文件默认为docker-compose.yml，可通过环境变量COMPOSE_FILE或-f参数自定义配置文件，其定义了多个有依赖关系的服务及每个服务运行的容器。**

**使用一个Dockerfile模板文件，可以让用户很方便的定义一个单独的应用容器。在工作中，经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个Web项目，除了Web服务容器本身，往往还需要再加上后端的数据库服务容器，甚至还包括负载均衡容器等。**

**Compose允许用户通过一个单独的docker-compose.yml模板文件（YAML 格式）来定义一组相关联的应用容器为一个项目（project）。**

**Docker-Compose项目由`Python`编写，调用Docker服务提供的API来对容器进行管理。因此，只要所操作的平台支持Docker API，就可以在其上利用Compose来进行编排管理。**



### Docker-compose模板文件简介

**Compose允许用户通过一个docker-compose.yml模板文件（YAML 格式）来定义一组相关联的应用容器为一个项目（project）。**

**Compose模板文件是一个定义服务、网络和卷的YAML文件。Compose模板文件默认路径是当前目录下的docker-compose.yml，可以使用.yml或.yaml作为文件扩展名。**

**Docker-Compose标准模板文件应该包含version、services、networks 三大部分，最关键的是services和networks两个部分。Compose目前有三个版本分别为Version 1，Version 2，Version 3，Compose区分Version 1和Version 2（Compose 1.6.0+，Docker Engine 1.10.0+）。Version 2支持更多的指令。Version 1将来会被弃用。更详细看[版本与协议的关系](https://docs.docker.com/compose/compose-file/compose-file-v2/)**

#### image

image是指定服务的镜像名称或镜像ID。如果镜像在本地不存在，Compose将会尝试拉取镜像。

```yaml
services:
    web:
        image: hello-world
```



#### build

服务除了可以基于指定的镜像，还可以基于一份Dockerfile，在使用up启动时执行构建任务，构建标签是build，可以指定Dockerfile所在文件夹的路径。Compose将会利用Dockerfile自动构建镜像，然后使用镜像启动服务容器。

```yaml
build: /path/ to /build/dir
```

也可以是相对路径，只要上下文确定就可以读取到Dockerfile

```yaml
build: ./dir
```

设定上下文根目录，然后以该目录为准指定Dockerfile

```yaml
build:
  context: ../
  dockerfile: path/ of /Dockerfile
```

build都是一个目录，如果要指定Dockerfile文件需要在build标签的子级标签中使用dockerfile标签指定。

如果同时指定image和build两个标签，那么Compose会构建镜像并且把镜像命名为image值指定的名字

#### context

context选项可以是Dockerfile的文件路径，也可以是到链接到git仓库的url，当提供的值是相对路径时，被解析为相对于撰写文件的路径，此目录也是发送到Docker守护进程的context

```yaml
build:
  context: ./dir
```

#### dockerfile

使用dockerfile文件来构建，必须指定构建路径

```yaml
build:
  context: .
  dockerfile: Dockerfile-alternate
```

#### commond

使用command可以覆盖容器启动后默认执行的命令

```yaml
command: bundle exec thin -p 3000
```

#### container_name

Compose的容器名称格式是：<项目名称><服务名称><序号>

可以自定义项目名称、服务名称，但如果想完全控制容器的命名，可以使用标签指定：

```yaml
container_name: app
```

#### depends_on

在使用Compose时，最大的好处就是少打启动命令，但一般项目容器启动的顺序是有要求的，如果直接从上到下启动容器，必然会因为容器依赖问题而启动失败。例如在没启动数据库容器的时候启动应用容器，应用容器会因为找不到数据库而退出。depends_on标签用于解决容器的依赖、启动先后的问题

```yaml
version: '2'
services:
  web:
    build: .
    depends_on:
      - db
      - redis
  redis:
    image: redis
  db:
    image: postgres
```

上述YAML文件定义的容器会先启动redis和db两个服务，最后才启动web 服务

#### PID

```yaml
pid: "host"
```

将PID模式设置为主机PID模式，跟主机系统共享进程命名空间。容器使用pid标签将能够访问和操纵其他容器和宿主机的名称空间

#### ports

ports用于映射端口的标签。

使用HOST:CONTAINER格式或者只是指定容器的端口，宿主机会随机映射端口

```yaml
ports:
 - "3000"
 - "8000:8000"
 - "49100:22"
 - "127.0.0.1:8001:8001"
```

当使用HOST:CONTAINER格式来映射端口时，如果使用的容器端口小于60可能会得到错误得结果，因为YAML将会解析xx:yy这种数字格式为60进制。所以建议采用字符串格式。

#### extra_hosts

添加主机名的标签，会在/etc/hosts文件中添加一些记录

```yaml
extra_hosts:
 - "somehost:162.242.195.82"
 - "otherhost:50.31.209.229"
```

#### volumes

挂载一个目录或者一个已存在的数据卷容器，可以直接使用 [HOST:CONTAINER]格式，或者使用[HOST:CONTAINER:ro]格式，后者对于容器来说，数据卷是只读的，可以有效保护宿主机的文件系统。

Compose的数据卷指定路径可以是相对路径，使用 . 或者 .. 来指定相对目录。

数据卷的格式可以是下面多种形式

```yaml
volumes:
  // 只是指定一个路径，Docker 会自动在创建一个数据卷（这个路径是容器内部的）。
  - /var/lib/mysql
  // 使用绝对路径挂载数据卷
  - /opt/data:/var/lib/mysql
  // 以 Compose 配置文件为中心的相对路径作为数据卷挂载到容器。
  - ./cache:/tmp/cache
  // 使用用户的相对路径（~/ 表示的目录是 /home/<用户目录>/ 或者 /root/）。
  - ~/configs:/etc/configs/:ro
  // 已经存在的命名的数据卷。
  - datavolume:/var/lib/mysql
```

如果不使用宿主机的路径，可以指定一个volume_driver。

```yaml
volume_driver: mydriver
```

#### volumes_from

从另一个服务或容器挂载其数据卷：

```yaml
volumes_from:
   - service_name   
     - container_name
```

#### dns

自定义DNS服务器。可以是一个值，也可以是一个列表

```yaml
dns: 8.8.8.8
dns: 
    - 8.8.8.8   
    - 9.9.9.9
```

#### expose

暴露端口，但不映射到宿主机，只允许能被连接的服务访问。仅可以指定内部端口为参数，如下所示：

```yaml
expose:
    - "3000"
    - "8000"
```

#### links

链接到其它服务中的容器。使用服务名称（同时作为别名），或者“服务名称:服务别名”（如 SERVICE:ALIAS），例如：

```yaml
links:
    - db
    - db:database
    - redis
```

#### net

设置网络模式

```yaml
net: "bridge"
net: "none"
net: "host"
net: "container"
```



### Docker-compose模板文件示例

**基于lnmp的禅道**

作业：[使用docker-compose搭建wordpress](https://github.com/docker/awesome-compose/blob/master/official-documentation-samples/wordpress/README.md)

#### 1.安装

**[官网安装方式](https://docs.docker.com/compose/install/)，这里我采用官网的安装方式，也就是方法一**

[下载地址：](https://github.com/docker/compose/releases)https://github.com/docker/compose/releases

方法一：

```shell
[root@docker ~]# DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}

[root@docker ~]# mkdir -p $DOCKER_CONFIG/cli-plugins

[root@docker ~]# curl -SL https://github.com/docker/compose/releases/download/v2.5.0/docker-compose-linux-x86_64 -o $DOCKER_CONFIG/cli-plugins/docker-compose

[root@docker ~]# chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose
```

方法二：

```shell
[root@docker ~]# mv docker-compose /usr/local/bin/docker-compose
[root@docker ~]# chmod a+x /usr/local/bin/docker-compose 

[root@docker ~]# docker-    # 用tab键是可以提示补全的
docker-compose  docker-init     docker-proxy    

[root@docker ~]# docker-compose version
Docker Compose version v2.5.0
```



#### 2.编写模板文件

```shell
[root@docker ~]# mkdir -p /docker/script
[root@docker ~]# cd !$
cd /docker/script
[root@docker script]# mkdir compose
[root@docker script]# cd compose/
[root@docker compose]# vim docker-compose.yaml
```

```yaml
version: '3'
services:
  db:
    image: mysql:5.7.36
    container_name: mysql
    restart: always
    tty: true
    environment:
      MYSQL_ROOT_PASSWORD: "123456"
    volumes:
      - /opt/data:/var/lib/mysql
    networks:					#其它容器都要同样的网络，但名字可以自定义
      - lnmp
  web:
    image: registry.cn-shenzhen.aliyuncs.com/adif0028/nginx_php:74v3
    container_name: web01
    restart: always
    tty: true
    depends_on:
      - db
    volumes:
      - /docker/wordpress:/usr/local/nginx/html
    ports:
      - 80:80
    networks:
      - lnmp
volumes:
  /opt/data:
  /docker/wordpress:
networks:
  lnmp:
```

```shell
# 上传禅道到/docker/script/compose下
[root@docker compose]# unzip ZenTaoPMS.12.3.2.zip 
[root@docker compose]# mv zentaopms/ zentao
```

#### 3.启动


```shell
[root@docker compose]# docker compose up   # 前台启动，docker-compose up这条命令也可以


[root@docker compose]# docker compose up -d   # 后台启动

[root@docker compose]# docker ps
```

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205291133525.png)

#### 4.修改配置文件

```shell
[root@docker compose]# docker exec -it 882cee75d749 bash
[root@882cee75d749 /]# cd /usr/local/nginx/conf/
[root@882cee75d749 conf]# vi nginx.conf

改: 71      root /usr/local/nginx/html;
为: 71      root /usr/local/nginx/html/www;


[root@882cee75d749 conf]# vi /usr/local/php/etc/php.ini
改: 1312 ;session.save_handler = files
为: 1312 session.save_handler = files

改: 1341 ;session.save_path = "/tmp"
为: 1341 session.save_path = "/tmp"

[root@882cee75d749 conf]# nginx -s reload
[root@882cee75d749 conf]# /etc/init.d/php-fpm restart
Gracefully shutting down php-fpm . done
Starting php-fpm  done


[root@882cee75d749 conf]# 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.21.0.3	882cee75d749


# 浏览器输入宿主机IP地址，到达数据库填写可以写db，因为compose里的yaml文件当时就已经定义好了，容器里面是有联系的
```

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205291144763.png)



### 总结

**注意compose文件需要特定的名字docker-compose.yaml**
**docker compose up -d (-d是后台启动，否则前台有输出启动)**
**关闭容器并且清理相关资源，清理容器，清理网络**
**docker compose down 也是在有yaml文件的目录下执行。**



## docker搭建registry仓库

镜像构建完成后，可以很容易的在当前宿主机上运行，但是，如果需要在其它服务器上使用这个镜像，我们就需要一个集中的存储、分发镜像的服务，[Docker Registry](../repository/registry.md) 就是这样的服务。

一个 **Docker Registry** 中可以包含多个**仓库**（`Repository`）；每个仓库可以包含多个**标签**（`Tag`）；每个标签对应一个镜像。

通常，一个仓库会包含同一个软件不同版本的镜像，而标签就常用于对应该软件的各个版本。我们可以通过 `<仓库名>:<标签>` 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签，将以 `latest` 作为默认标签。

以 [Ubuntu 镜像](https://store.docker.com/images/ubuntu) 为例，`ubuntu` 是仓库的名字，其内包含有不同的版本标签，如，`14.04`, `16.04`。我们可以通过 `ubuntu:14.04`，或者 `ubuntu:16.04` 来具体指定所需哪个版本的镜像。如果忽略了标签，比如 `ubuntu`，那将视为 `ubuntu:latest`。

仓库名经常以 *两段式路径* 形式出现，比如 `jwilder/nginx-proxy`，前者往往意味着 Docker Registry 多用户环境下的用户名，后者则往往是对应的软件名。但这并非绝对，取决于所使用的具体 Docker Registry 的软件或服务。



### Docker Registry 公开服务

Docker Registry 公开服务是开放给用户使用、允许用户管理镜像的 Registry 服务。一般这类公开服务允许用户免费上传、下载公开的镜像，并可能提供收费服务供用户管理私有镜像。

最常使用的 Registry 公开服务是官方的 [Docker Hub](https://hub.docker.com/)，这也是默认的 Registry，并拥有大量的高质量的官方镜像。除此以外，还有 [CoreOS](https://coreos.com/) 的 [Quay.io](https://quay.io/repository/)，CoreOS 相关的镜像存储在这里；Google 的 [Google Container Registry](https://cloud.google.com/container-registry/)，[Kubernetes](http://kubernetes.io/) 的镜像使用的就是这个服务。

由于某些原因，在国内访问这些服务可能会比较慢。国内的一些云服务商提供了针对 Docker Hub 的镜像服务（`Registry Mirror`），这些镜像服务被称为**加速器**。常见的有 [阿里云加速器](c-users-fuguo-appdata-local-temp-gitbook2lark-1351647b5e806d023e)  一节中有详细的配置方法。

国内也有一些云服务商提供类似于 Docker Hub 的公开服务。比如 [时速云镜像仓库](https://hub.tenxcloud.com/)、[网易云镜像服务](https://c.163.com/hub#/m/library/)、[DaoCloud 镜像市场](https://hub.daocloud.io/)、[阿里云镜像库](https://cr.console.aliyun.com) 等。



### 私有 Docker Registry

除了使用公开服务外，用户还可以在本地搭建私有 Docker Registry。Docker 官方提供了 [Docker Registry](c-users-fuguo-appdata-local-temp-gitbook2lark-1351647b5e806d023e) 一节中，会有进一步的搭建私有 Registry 服务的讲解。

开源的 Docker Registry 镜像只提供了 [Docker Registry API](https://docs.docker.com/registry/spec/api/) 的服务端实现，足以支持 `docker` 命令，不影响使用。但不包含图形界面，以及镜像维护、用户管理、访问控制等高级功能。在官方的商业化版本 [Docker Trusted Registry](https://docs.docker.com/datacenter/dtr/2.0/) 中，提供了这些高级功能。

除了官方的 Docker Registry 外，还有第三方软件实现了 Docker Registry API，甚至提供了用户界面以及一些高级功能。比如，[VMWare Harbor](https://github.com/vmware/harbor) 和 [Sonatype Nexus](https://www.sonatype.com/docker)。



### 搭建私有的registry

#### 1.拉取镜像

```shell
[root@docker ~]# docker pull registry
```



#### 2.启动

```shell
[root@docker ~]# docker run -d -p 5000:5000 --restart=always --name registry -v /opt/myregistry:/var/lib/registry registry
e1eb131be448e653a40f5eb742ae38bdc3b503c1f1e0d1316b30646e905e98e3

[root@docker ~]# docker ps
CONTAINER ID   IMAGE                                                                COMMAND                  CREATED         STATUS         PORTS                                       NAMES
e1eb131be448   registry                                                             "/entrypoint.sh /etc…"   5 seconds ago   Up 3 seconds   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   registry


# 浏览器输入宿主机IP地址:5000
# 在没有任何东西的时候打开是空白的
```

 ![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205291437746.png)

#### 3.推送镜像

操作跟推送上阿里云一样的操作

```shell
# 打标签
[root@docker ~]# docker images
REPOSITORY                                            TAG              IMAGE ID       CREATED        SIZE
alpine                                                latest           c059bfaa849c   6 months ago   5.59MB

[root@docker ~]# docker tag c059bfaa849c 192.168.188.70:5000/alpine:v1



# 上传
[root@docker ~]# docker push 192.168.188.70:5000/alpine:v1
The push refers to repository [192.168.188.70:5000/alpine]
Get "https://192.168.188.70:5000/v2/": http: server gave HTTP response to HTTPS client
[root@docker ~]#


# 遇到报错The push refers to repository [192.168.188.70:5000/alpine] Get "https://192.168.188.70:5000/v2/": http: server gave HTTP response to HTTPS client

#为什么需要增加此配置呢？docker默认采用https的方式推送镜像，如果不进行此配置，则走https协议，此时我们安装的repositry并不支持https

# 解决方案
[root@docker ~]# vim /etc/docker/daemon.json 
# 增加这一项
"insecure-registries": ["192.168.188.70:5000"]

# 完整是
{
  "registry-mirrors": ["https://niphmo8u.mirror.aliyuncs.com"],
  "insecure-registries": ["192.168.188.70:5000"]
}


[root@docker ~]# systemctl restart docker
```

```shell
# 重新上传
[root@docker ~]# docker push 192.168.188.70:5000/alpine:v1

# 浏览器访问http://192.168.188.70:5000/v2/  ；根据前面提示信息里有，但是这里没有采用https，所以换成http
```

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205291446958.png)

#### 4.查看镜像列表

```shell
# 浏览器输入 http://192.168.188.70:5000/v2/_catalog 可以查看推送上的镜像
```

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205291448535.png)



#### 5.查看镜像标签

```shell
# 浏览器输入 http://192.168.188.70:5000/v2/alpine/tags/list


# 宿主机查看
[root@docker ~]# ls /opt/myregistry/docker/registry/v2/repositories/alpine/
_layers  _manifests  _uploads
```

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205291450897.png)

#### 6.带basic认证的registry

就是相当于阿里云镜像仓库的登陆

```shell
yum install httpd-tools -y
mkdir /opt/registry-var/auth/ -p
htpasswd  -Bbn shy 123456  >> /opt/registry-var/auth/htpasswd


docker rm -f registry

# 启动
docker run -d -p 5000:5000 -v /opt/registry-var/auth/:/auth/ -v /opt/myregistry:/var/lib/registry -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e  "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" registry 
```

```
docker login 192.168.188.70:5000
docker push 192.168.188.70:5000/alpine:v1
```



#### 7.删除镜像

```shell
1）进入docker registry的容器中

docker exec -it registry /bin/sh

2) 删除repo

rm -fr /var/lib/registry/docker/registry/v2/repositories/nginx

3) 清除掉blob

registry garbage-collect /etc/docker/registry/config.yml
```



## Docker跨主机容器之间的通信macvlan

默认一个物理网卡，只有一个物理地址，虚拟多个mac地址；基于二层



### 实验环境

|  主机名   |       IP       |  备注  |
| :-------: | :------------: | :----: |
|  docker   | 192.168.188.70 | docker |
| docker-71 | 192.168.188.71 | docker |

**目的：实现容器基于macvlan的单网段跨主机通信**



### 1.创建网络

```shell
# 70的机子

[root@docker compose]# ifconfig   # 确认自己的网卡


# 创建macvlan网络，指定网段、网关等信息
[root@docker compose]# docker network create --driver macvlan --subnet 10.0.0.0/24 --gateway 10.0.0.254 -o parent=ens33 macvlan_1

# 查看docker有什么网络
[root@docker compose]# docker network list   # container和macvlan、overlay是需要创建才会出现，其他都是默认有的
NETWORK ID     NAME           DRIVER    SCOPE
ff04f1f2a772   bridge         bridge    local
77e4bd1d47af   compose_lnmp   bridge    local
fe2a52aeaa07   host           host      local
d934bcc430b5   macvlan_1      macvlan   local
10f9ba31708a   none           null      local

# 开启ens33网卡的混杂模式，也就是开启网卡的多个虚拟interface（接口）
[root@docker compose]# ip link set ens33 promisc on
```

```shell
# 71的机子

[root@docker-71 compose]# ifconfig   # 确认自己的网卡


# 创建macvlan网络，指定网段、网关等信息
[root@docker-71 ~]# docker network create --driver macvlan --subnet 10.0.0.0/24 --gateway 10.0.0.254 -o parent=ens33 macvlan_1


# 查看docker-71有什么网络
[root@docker-71 ~]# docker network list
NETWORK ID     NAME        DRIVER    SCOPE
1753cd6d5fcc   bridge      bridge    local
fe2a52aeaa07   host        host      local
20ea7618f39f   macvlan_1   macvlan   local
10f9ba31708a   none        null      local

# 开启ens33网卡的混杂模式，也就是开启网卡的多个虚拟interface（接口） 
[root@docker-71 ~]# ip link set ens33 promisc on
```



### 2.启动容器指定网络

```shell
# 70的机子

# 基于新创建的macvlan网络运行一个容器，并指定其IP
[root@docker compose]# docker run -it --network macvlan_1 --ip=10.0.0.200 centos:7
[root@7afc1f78d410 /]#    # 注意这里无法走外网
```

```shell
# 71的机子
# 基于新创建的macvlan网络运行一个容器，并指定其IP
[root@docker-71 ~]# docker run -it --network macvlan_1 --ip=10.0.0.201 centos:7
[root@b547ebdbb223 /]#
```



### 3.验证

```shell
# 互ping

# 70
[root@7afc1f78d410 /]# ping 10.0.0.201


# 71
[root@b547ebdbb223 /]# ping 10.0.0.200
```



## Docker跨主机容器通信之overlay

http://www.cnblogs.com/CloudMan6/p/7270551.html

暂未实操，基于三层；在k8s中体现，使用网络插件flannel

```shell
1）准备工作
docker01上：
docker run -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap
设置容器的主机名

consul：kv类型的存储数据库（key:value）
docker01、02上：
vim  /etc/docker/daemon.json
{
  "hosts":["tcp://0.0.0.0:2376","unix:///var/run/docker.sock"],
  "cluster-store": "consul://10.0.0.13:8500",
  "cluster-advertise": "10.0.0.11:2376"
}

vim /etc/docker/daemon.json 
vim /usr/lib/systemd/system/docker.service
systemctl daemon-reload 
systemctl restart docker

2）创建overlay网络
docker network create -d overlay --subnet 172.16.1.0/24 --gateway 172.16.1.254 ol1

3）启动容器测试
docker run -it --network ol1 --name oldboy01  busybox /bin/bash
每个容器有两块网卡,eth0实现容器间的通讯,eth1实现容器访问外网
```



### 总结

**docker跨节点网络方案:端口映射、host模式、macvlan、overlay**



## Harbor

docker企业级镜像仓库harbor(vmware 中国团队)

Github地址https://github.com/goharbor/harbor

官方地址：https://github.com/goharbor/harbor/releases

我这里选择离线安装，把包下载下来



### 1.上传解压缩

```shell
[root@docker ~]# ls
anaconda-ks.cfg  harbor-offline-installer-v2.5.0.tgz
[root@docker ~]# tar xf harbor-offline-installer-v2.5.0.tgz
[root@docker ~]# ls
anaconda-ks.cfg  harbor  harbor-offline-installer-v2.5.0.tgz
```



### 2.修改文件

```shell
[root@docker ~]# cd harbor
[root@docker harbor]# ls
common.sh  harbor.v2.5.0.tar.gz  harbor.yml.tmpl  install.sh  LICENSE  prepare
[root@docker harbor]# cp harbor.yml.tmpl harbor.yml

[root@docker harbor]# vim harbor.yml
改: 5 hostname: reg.mydomain.com
为: 5 hostname: 192.168.188.70

改: 注释掉https(443)


改: 34 harbor_admin_password: Harbor12345
为: 34 harbor_admin_password: 123456


改: 数据库密码生产上需要改，这是dev就不改了


改: 47 data_volume: /data
为: 47 data_volume: /data/harbordata


[root@docker harbor]# mkdir -p /data/harbordata
```



### 3.安装

```shell
[root@docker harbor]# ./install.sh
```

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205291633170.png)



### 4.验证

```shell
[root@docker harbor]# docker ps

# 浏览器输入宿主机的IP地址
```

![](https://figure-bed-1304788733.cos.ap-guangzhou.myqcloud.com/typora/202205291640383.png)



**操作与阿里云一样**



<font color='red'>**注意：修改docker配置文件，增加如下内容**</font>

<font color='red'>**"insecure-registries": [ "http://192.168.188.70"]**</font>

**<font color='red'>然后重启服务systemctl restart docker</font>**

<font color='red'>**为什么需要增加此配置呢？docker默认采用https的方式推送镜像，如果不进行此配置，则走https协议，此时我们安装的harbor并不支持https**</font>

