文章目录
- Docker教案
-
- Docker的安装
-
- 配置镜像加速器(华为云)
- [Docker C/S分离部署](#Docker C/S分离部署)
- Docker介绍
-
- [Docker 核心概念](#Docker 核心概念)
- [Docker 架构](#Docker 架构)
- 镜像
-
- 最小的镜像
- base镜像
- 镜像的分层结构
- 构建镜像
-
- [docker commit](#docker commit)
- Dockerfile构建镜像
- 镜像的缓存特性
- [调试 Dockerfile](#调试 Dockerfile)
- Dockerfile常用指令
- [RUN 、 CMD 和 ENTRYPOINT 区别](#RUN 、 CMD 和 ENTRYPOINT 区别)
-
- [Shell 和 Exec 格式](#Shell 和 Exec 格式)
- RUN
- CMD
- ENTRYPOINT
- 案例1:配置SSH镜像
- 案例2:自定义httpd镜像
- 镜像命名
- 公共仓库-dockerhub
- 搭建本地仓库
-
- Registry
- [企业级私有仓库 Harbor](#企业级私有仓库 Harbor)
- Docker镜像小结
- 容器
-
- 什么是容器
- 容器的作用
- 运行容器
- 进入容器
-
- [docker attach](#docker attach)
- [docker exec](#docker exec)
- [attach 与 exec 区别](#attach 与 exec 区别)
- 限制容器对内存的使用
- 限制容器对CPU的使用
- 容器的导入导出
- 网络
- 存储
-
- [storage driver](#storage driver)
- [Data Volume](#Data Volume)
-
- [bind mount](#bind mount)
- [docker managed volume](#docker managed volume)
- 共享数据
-
- [容器与 host 共享数据](#容器与 host 共享数据)
- 容器之间共享数据
- volume生命周期管理
- 容器监控
- 容器日志
- docker图形界面管理
-
- [DockerUI 容器管理器的安装与使用](#DockerUI 容器管理器的安装与使用)
- [Docker 图形化界面管理工具 Portainer](#Docker 图形化界面管理工具 Portainer)
Docker教案
Docker的安装
直接操作的环境:https://labs.play-with-docker.com/
环境选择
容器需要管理工具、runtime 和操作系统,我们的选择如下:
- 管理工具 - Docker Engine,Docker 最流行使用最广泛。
- runtime - runc,Docker 的默认 runtime
- 操作系统 - CentOS Stream8
安装操作系统
基于CentOS-Stream-8模板克隆一个虚拟机命名为docker,并配置静态IP 192.168.108.30,主机名改为docker
bash
[root@localhost ~]# hostnamectl set-hostname docker
[root@localhost ~]# nmcli connection modify ens160 ipv4.method manual ipv4.addresses 192.168.108.30/24 ipv4.gateway 192.168.108.2 ipv4.dns 192.168.108.2 autoconnect yes
[root@localhost ~]# nmcli con up ens160
安装 Docker
Docker 支持几乎所有的 Linux 发行版,也支持 Mac 和 Windows。各操作系统的安装方法可以访问:https://docs.docker.com/engine/installation/
卸载旧版本
bash
[root@docker ~]# yum remove docker-ce
安装必要工具
bash
[root@localhost ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 vim
[root@localhost ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
Adding repo from: https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
[root@localhost ~]# yum makecache
Docker CE Stable - x86_64 57 kB/s | 66 kB 00:01
CentOS Stream 8 - BaseOS 8.3 kB/s | 3.9 kB 00:00
CentOS Stream 8 - AppStream 9.8 kB/s | 4.4 kB 00:00
Metadata cache created.
allinone部署
安装软件
bash
[root@docker ~]# yum install -y docker-ce
配置服务
bash
[root@docker ~]# systemctl enable docker.service --now
验证安装
查看docker版本
bash
[root@docker ~]# docker --version
Docker version 26.1.3, build b72abbb
验证docker状态
bash
[root@docker ~]# systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
Active: active (running) since Wed 2025-09-03 13:51:07 CST; 36s ago
Docs: https://docs.docker.com
Main PID: 1813 (dockerd)
Tasks: 10
Memory: 135.7M
CGroup: /system.slice/docker.service
└─1813 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
配置镜像加速器(华为云)



bash
[root@docker ~]# vi /etc/docker/daemon.json
{
"registry-mirrors": [ "https://054b8ac70e8010d90f2ac00ef29e6580.mirror.swr.myhuaweicloud.com" ]
}
[root@docker ~]# systemctl restart docker
[root@docker ~]# docker info
Client: Docker Engine - Community
Version: 26.1.3
Context: default
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc.)
Version: v0.14.0
Path: /usr/libexec/docker/cli-plugins/docker-buildx
compose: Docker Compose (Docker Inc.)
Version: v2.27.0
Path: /usr/libexec/docker/cli-plugins/docker-compose
......
Registry Mirrors:
`https://054b8ac70e8010d90f2ac00ef29e6580.mirror.swr.myhuaweicloud.com/
Live Restore Enabled: false
Docker C/S分离部署
基于CentOS-Stream-8模板克隆两个虚拟机命名为docker_client和docker_server
docker server端配置
配置ip和主机名
bash
[root@localhost ~]# hostnamectl set-hostname docker_server
[root@localhost ~]# nmcli connection modify ens160 ipv4.method manual ipv4.addresses 192.168.108.30/24 ipv4.gateway 192.168.108.2 ipv4.dns 192.168.108.2 autoconnect yes
[root@localhost ~]# nmcli con up ens160
安装软件
bash
[root@docker_server ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 vim
[root@localhost ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
Adding repo from: https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
[root@docker_server ~]# yum makecache
[root@docker_server ~]# yum install -y docker-ce
[root@docker_server ~]# systemctl enable docker.service --now
[root@docker_server ~]# vi /etc/docker/daemon.json
{
"registry-mirrors": [ "https://054b8ac70e8010d90f2ac00ef29e6580.mirror.swr.myhuaweicloud.com" ]
}
[root@docker_server ~]# systemctl restart docker
配置服务
bash
[root@docker_server ~]# vim /usr/lib/systemd/system/docker.service
# 在ExecStart参数中最后添加 -H tcp://0.0.0.0:2375,docker默认监听2375
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375
[root@docker_server ~]# systemctl daemon-reload
[root@docker_server ~]# systemctl restart docker.service
[root@docker_server ~]# systemctl stop firewalld
配置效果如下

验证
bash
[root@docker_server ~]# yum install lsof
[root@docker_server ~]# lsof -i :2375
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
dockerd 5440 root 3u IPv6 44991 0t0 TCP *:docker (LISTEN)
docker_client端
配置ip与主机名
bash
[root@localhost ~]# hostnamectl set-hostname docker_client
[root@localhost ~]# nmcli connection modify ens160 ipv4.method manual ipv4.addresses 192.168.108.31/24 ipv4.gateway 192.168.108.2 ipv4.dns 192.168.108.2 autoconnect yes
[root@localhost ~]# nmcli con up ens160
只安装docker客户端
bash
[root@docker-client ~]# yum install -y yum-utils device-mapper-persistent-data lvm2 vim
[root@docker-client ~]# yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
Adding repo from: https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
[root@docker-client ~]# yum makecache
[root@docker-client ~]# yum install -y docker-ce-cli
验证
bash
[root@docker_client ~]# docker run hello-world #client直接执行报错,没有装服务端
docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?.
See 'docker run --help'.
# client端连接server端执行命令
[root@docker-client ~]# docker -H 192.168.108.30 run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
......
[root@docker-client ~]# docker -H 192.168.108.30 images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d2c94e258dcb 17 months ago 13.3kB
说明:client只做管理,image和container存储在server端。
Docker介绍
Docker是基于Go语言实现的开源容器项目
Docker提供了各种容器管理工具 ,让用户可以更简单明了地管理和使用容器;其次,Docker引入分层文件系统构建和高效的镜像机制降低了迁移难度,极大地提升了用户体验。
可以将Docker容器理解为一种轻量级的沙盒 。每个容器内运行着一个应用,不同的容器相互隔离,容器之间也可以通过网络互相通信。

Docker 核心概念
Docker的大部分操作都围绕着它的三大核心概念------镜像、容器和仓库。
Docker镜像
Docker镜像类似于虚拟机镜像,镜像是创建Docker容器的基础。
Docker容器
Docker容器类似于一个轻量级的沙箱,Docker利用容器来运行和隔离应用。容器是从镜像创建的应用运行实例。容器都是彼此相互隔离的、互不可见的。
Docker仓库
Docker仓库是Docker集中存放镜像文件的场所。仓库注册服务器存放着很多类镜像,每类镜像包括多个镜像文件,通过不同的标签(tag)来进行区分。
根据所存储的镜像公开分享与否,Docker仓库可以分为:
- 公开仓库(Public)
- 私有仓库(Private)
Docker 架构
完整的Docker由以下几部分构成:
-
守护进程(Daemon):Docker守护进程(dockerd)侦听Docker API请求并管理Docker对象,,如图像、容器、网络和卷。守护进程还可以与其他守护进程通信来管理Docker服务
-
REST API: 主要与Docker Daemon进行交互
-
客户端(Docker Client): 它是与Docker交互的主要方式,通过命令行接口(CLI)客户端(docker命令),客户机将命令通过REST API发送给并执行其命令
-
Register Repository 镜像仓库: Docker注册表存储Docker镜像
-
Image 镜像: 镜像是一个只读模板,带有创建Docker容器的指令
-
Container 容器: 容器是镜像的可运行实例
-
Services : Docker引擎支持集群模式服务允许您跨多个Docker守护进程扩展管理容器,服务允许您定义所需的状态,对于使用者来说Docker服务看起来是一个单独的应用程序
Docker 架构如下图所示:

Docker 采用的是 Client/Server 架构。客户端向服务器发送请求,服务器负责构建、运行和分发容器。客户端和服务器可以运行在同一个 Host 上,客户端也可以通过 socket 或 REST API 与远程的服务器通信
镜像
最小的镜像
镜像是 Docker 容器的基石,容器是镜像的运行实例,有了镜像才能启动容器。
hello-world - 最小的镜像
hello-world 是 Docker 官方提供的一个镜像,通常用来验证 Docker 是否安装成功。
我们先通过 docker pull 从 Docker Hub 下载它。
shell
[root@docker ~]# docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
c1ec31eb5944: Pull complete
Digest: sha256:91fb4b041da273d5a3273b6d587d62d518300a6ad268b28628f74997b93171b2
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest
用 docker images 命令查看镜像的信息。
shell
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest d2c94e258dcb 16 months ago 13.3kB
通过 docker run 运行。
shell
[root@docker ~]# docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
.......
base镜像
base 镜像有两层含义:
- 不依赖其他镜像,从 scratch 构建。
- 其他镜像可以之为基础进行扩展。
所以,能称作 base 镜像的通常都是各种 Linux 发行版的 Docker 镜像,比如 Ubuntu, Debian, CentOS 等。
镜像的分层结构
Docker 支持通过扩展现有镜像,创建新的镜像。
Docker 镜像采用分层结构的作用:共享资源。
可写的容器层
当容器启动时,一个新的可写层被加载到镜像的顶部。
这一层通常被称作"容器层","容器层"之下的都叫"镜像层"。

只有容器层是可写的,容器层下面的所有镜像层都是只读的。
构建镜像
Docker 提供了两种构建镜像的方法:
- docker commit 命令
- Dockerfile 构建文件
docker commit
docker commit 包含三个步骤:
- 运行容器
- 修改容器
- 将容器保存为新的镜像
例子:在 ubuntu base 镜像中安装 vim并保存为新镜像。
运行容器
shell
[root@docker ~]# docker run -it ubuntu
root@8dbdff6d3d88:/#
-it 以交互模式进入容器,并打开终端
安装 vim
shell
root@8dbdff6d3d88:/# apt-get update
root@8dbdff6d3d8:/# apt-get install -y vim
保存为新镜像 ubuntu-with-vim
bash
[root@docker ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8dbdff6d3d88 ubuntu "/bin/bash" 2 minutes ago Up 2 minutes cool_darwin
shell
[root@docker ~]# docker commit cool_darwin ubuntu-with-vim
sha256:ba18ae460c068f9bdba060350e64dcec4bc4af05b9918602ee34e6350d0369a4
查看新镜像的属性
bash
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu-with-vim latest acefd029083b 27 minutes ago 189MB
ubuntu latest edbfe74c41f8 5 weeks ago 78.1MB
验证
shell
[root@docker ~]# docker run -it ubuntu-with-vim #ubuntu-with-vim是新创建的镜像名
root@4d071cf3014f:/# which vim
/usr/bin/vim
root@4d071cf3014f:/# vim file1
Dockerfile构建镜像
Dockerfile 是一个文本文件,记录了镜像构建的所有步骤。
Dockerfile内容基础知识:
- 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
- 指令按照从上到下,顺序执行
- 每条指令都会创建一个新的镜像层并对镜像进行提交
常用参数:
docker build -f [Dockerfile路径] [构建上下文路径]
| 参数 | 作用 |
|---|---|
-f 或 --file |
标志符,声明要使用自定义 Dockerfile |
[Dockerfile路径] |
绝对路径 或相对于构建上下文的路径 (如 subdir/Dockerfile.dev) |
[构建上下文路径] |
Docker 打包发送给守护进程的目录(通常用 . 表示当前目录) |
使用Dockerfile 创建拥有vim功能的ubuntu镜像
bash
[root@docker ~]# cd /root
[root@docker ~]# vim Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y vim
[root@docker ~]# docker build -t ubuntu-with-vim-dockerfile .
-t将新镜像命名为ubuntu-with-vim-dockerfile,命令末尾的.指明 build context 为当前目录。Docker 默认会从 build context 中查找 Dockerfile 文件,我们也可以通过-f参数指定 Dockerfile 的位置。
查看镜像分层结构
ubuntu-with-vim-dockerfile 是通过在 base 镜像的顶部添加一个新的镜像层而得到的

这个新镜像层的内容由 RUN apt-get update && apt-get install -y vim 生成
docker history 会显示镜像的构建历史,也就是 Dockerfile 的执行过程。
镜像的缓存特性
Docker 会缓存已有镜像的镜像层,构建新镜像时,如果某镜像层已经存在,就直接使用,无需重新创建。
bash
[root@docker ~]# touch testfile
[root@docker ~]# ls
Dockerfile testfile
[root@docker ~]# vim Dockerfile
[root@docker ~]# cat Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y vim
COPY testfile /
[root@docker ~]# docker build -t ubuntu-with-vim-dockerfile-2 .
之前已经运行过相同的 RUN 指令,这次直接使用缓存中的镜像层,在 ubuntu-with-vi-dockerfile 镜像上直接添加一层就得到了新的镜像 ubuntu-with-vim-dockerfile-2

如果我们希望在构建镜像时不使用缓存,可以在 docker build 命令中加上 --no-cache 参数
Dockerfile 中每一个指令都会创建一个镜像层,上层是依赖于下层的。只要某一层发生变化,其上面所有层的缓存都会失效;除了构建时使用缓存,Docker 在下载镜像时也会使用。
调试 Dockerfile
如果 Dockerfile 由于某种原因执行到某个指令失败了,我们也将能够得到前一个指令成功执行构建出的镜像,可以运行最新的这个镜像定位指令失败的原因
bash
[root@docker ~]# ls
Dockerfile testfile
[root@docker ~]# vim Dockerfile
FROM busybox
RUN touch tmpfile
RUN /bin/bash -c "echo continue to build..."
COPY testfile /
[root@docker ~]# docker build -t image-debug .

Dockerfile 在执行第三步 RUN 指令时失败。我们可以利用busybox的镜像进行调试:

bash
[root@docker ~]# vim Dockerfile
FROM busybox
RUN touch tmpfile
RUN /bin/sh -c "echo continue to builld..."
COPY testfile /
[root@docker ~]# docker build -t image-debug .
Dockerfile常用指令
FROM
指定 base 镜像,第一条必须是FROM
MAINTAINER
设置镜像的作者,可以是任意字符串
COPY
将文件从 build context 复制到镜像。
COPY 支持两种形式:
- COPY src dest
- COPY ["src", "dest"]
注意:src 只能指定 build context 中的文件或目录
ADD
与 COPY 类似,从 build context 复制文件到镜像。不同的是,如果 src 是归档文件(tar, zip, tgz, xz 等),文件会被自动解压到 dest
ENV
设置环境变量,环境变量可被后面的指令使用
EXPOSE
指定容器中的进程会监听某个端口
VOLUME
将文件或目录声明为 volume
WORKDIR
为后面的 RUN, CMD, ENTRYPOINT, ADD 或 COPY 指令设置镜像中的当前工作目录
RUN
在容器中运行指定的命令
CMD
容器启动时运行指定的命令;Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效;CMD 可以被 docker run 之后的参数替换
ENTRYPOINT
设置容器启动时运行的命令;Dockerfile 中可以有多个 ENTRYPOINT 指令,但只有最后一个生效;CMD 或 docker run 之后的参数会被当做参数传递给 ENTRYPOINT
编写如下的 Dockerfile:
dockerfile
FROM busybox #从busybox开始构建
MAINTAINER 6946630@qq.com #声明作者信息
WORKDIR /testdir #设置工作目录为/testdir
RUN touch tmpfile1 #在新镜像中创建tmpfille1
COPY ["tmpfile2","."] #将Dockerfile文件所在目录中的tmpfile2文件拷贝到新镜像中
ADD ["passwd.tar.gz","."] #将Dockerfile文件所在目录中的passwd.tar.gz拷贝到新镜像中并解压缩
ENV WELCOME "You are in my container,welcome!" #设置环境变量WELOCME
bash
[root@docker ~]# touch tmpfile2
[root@docker ~]# cp /etc/passwd .
[root@docker ~]# tar -cvzf passwd.tar.gz passwd
passwd
[root@docker ~]# rm passwd
[root@docker ~]# vim Dockerfile
FROM busybox
MAINTAINER 6946630@qq.com
WORKDIR /testdir
RUN touch tmpfile1
COPY ["tmpfile2","."]
ADD ["passwd.tar.gz","."]
ENV WELCOME "You are in my container,welcome!"
[root@docker ~]# ls
Dockerfile passwd.tar.gz tmpfile2
[root@docker ~]# docker build -t my-image .
运行容器,验证镜像内容:

RUN 、 CMD 和 ENTRYPOINT 区别
- RUN 执行命令并创建新的镜像层,RUN 经常用于安装软件包。
- CMD 设置容器启动后默认执行的命令及其参数,但 CMD 能够被
docker run后面跟的命令行参数替换。 - ENTRYPOINT 配置容器启动时运行的命令。
Shell 和 Exec 格式
我们可用两种方式指定 RUN、CMD 和 ENTRYPOINT 要运行的命令:Shell 格式和 Exec 格式
Shell 格式
dockerfile
RUN apt-get install python3
CMD echo "Hello world"
ENTRYPOINT echo "Hello world"
当指令执行时,shell 格式底层会调用 /bin/sh -c 命令
dockerfile
[root@docker ~]# vim Dockerfile
FROM busybox
ENV name stj
ENTRYPOINT echo "Hello, $name"
测试
bash
[root@docker ~]# docker build -t dockerfile1 .
[root@docker ~]# docker run dockerfile1
Hello,stj
注 :环境变量 name 已经被值 stj 替换。
Exec 格式
dockerfile
RUN ["apt-get", "install", "python3"]
CMD ["/bin/echo", "Hello world"]
ENTRYPOINT ["/bin/echo", "Hello world"]
当指令执行时,会直接调用 命令,不会被 shell 解析
dockerfile
[root@docker ~]# vim Dockerfile
FROM busybox
ENV name stj
ENTRYPOINT ["/bin/echo", "Hello, $name"]
测试
bash
[root@docker ~]# docker build -t dockerfile2 .
[root@docker ~]# docker run dockerfile2
hello,$name
注:环境变量"name"没有被替换。
如果希望使用环境变量,照如下修改:
dockerfile
[root@docker ~]# vim Dockerfile
FROM busybox
ENV name stj
ENTRYPOINT ["/bin/sh", "-c", "echo Hello, $name"]
CMD 和 ENTRYPOINT 推荐使用 Exec 格式,因为指令可读性更强,更容易理解;RUN 则两种格式都可以。
RUN
RUN 指令通常用于安装应用和软件包。
RUN 在当前镜像的顶部执行命令,并通过创建新的镜像层。Dockerfile 中常常包含多个 RUN 指令。
RUN 有两种格式:
- Shell 格式:RUN
- Exec 格式:RUN ["executable", "param1", "param2"]
dockerfile
[root@docker ~]# vim Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y \
bzr \
cvs \
git \
mercurial \
subversion
注意:apt-get update 和 apt-get install 被放在一个 RUN 指令中执行,这样能够保证每次安装的是最新的包;如果 apt-get install 在单独的 RUN 中执行,则会使用 apt-get update 创建的镜像层,而这一层可能是很久以前缓存的。
CMD
CMD 指令允许用户指定容器的默认执行的命令。
此命令会在容器启动且 docker run 没有指定其他命令时运行。
CMD 有三种格式:
- Exec 格式:CMD ["executable","param1","param2"] 这是 CMD 的推荐格式
- CMD ["param1","param2"] 为 ENTRYPOINT 提供额外的参数,此时 ENTRYPOINT 必须使用 Exec 格式
- Shell 格式:CMD command param1 param2
dockerfile
[root@docker ~]# vim Dockerfile
FROM busybox
CMD echo "Hello,world"
测试
bash
[root@docker ~]# docker build -t dockerfile5 .
[root@docker ~]# docker run -it dockerfile5
Hello,world
[root@docker ~]# docker run -it dockerfile5 /bin/sh
/ #
ENTRYPOINT
ENTRYPOINT 指令可让容器以应用程序或者服务的形式运行。
ENTRYPOINT 不会被忽略,一定会被执行,即使运行 docker run 时指定了其他命令。
ENTRYPOINT 有两种格式:
- Exec 格式:ENTRYPOINT ["executable", "param1", "param2"] 这是 ENTRYPOINT 的推荐格式
- Shell 格式:ENTRYPOINT command param1 param2
在为 ENTRYPOINT 选择格式时必须小心,因为这两种格式的效果差别很大。
Exec 格式
ENTRYPOINT 的 Exec 格式用于设置要执行的命令及其参数,同时可通过 CMD 提供额外的参数。
ENTRYPOINT 中的参数始终会被使用,而 CMD 的额外参数可以在容器启动时动态替换掉:
dockerfile
[root@docker ~]# vim Dockerfile
FROM busybox
ENTRYPOINT ["/bin/echo", "Hello"]
CMD ["world"]
测试
bash
[root@docker ~]# docker build -t dockerfile6 .
[root@docker ~]# docker run -it dockerfile6
Hello world
[root@docker ~]# docker run -it dockerfile6 stj
Hello stj
Shell 格式
ENTRYPOINT 的 Shell 格式会忽略任何 CMD 或 docker run 提供的参数:
dockerfile
FROM busybox
ENTRYPOINT echo "Hello,"
CMD ["world"]
测试
bash
[root@docker ~]# docker build -t dockerfile7 .
[root@docker ~]# docker run -it dockerfile7
Hello,
[root@docker ~]# docker run -it dockerfile7 stj
Hello,
案例1:配置SSH镜像
制作一个带SSH功能的centos镜像
创建 dockerfile
bash
[root@docker ~]# vim centos.ssh.dockerfile
FROM centos:8.4.2105
RUN minorver=8.4.2105 && \
sed -e "s|^mirrorlist=|#mirrorlist=|g" \
-e "s|^#baseurl=http://mirror.centos.org/\$contentdir/\$releasever|baseurl=https://mirrors.aliyun.com/centos-vault/$minorver|g" \
-i.bak \
/etc/yum.repos.d/CentOS-*.repo
RUN yum install -y openssh-server
RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key
RUN ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key
RUN echo "root:huawei" | chpasswd
EXPOSE 22
CMD ["/usr/sbin/sshd","-D"]
构建镜像
bash
[root@docker ~]# docker build -t centos:ssh -f centos.ssh.dockerfile .
查看镜像创建过程
bash
[root@docker ~]# docker history centos:ssh
IMAGE CREATED CREATED BY SIZE COMMENT
cc138c4d3c36 36 seconds ago CMD ["/usr/sbin/sshd" "-D"] 0B buildkit.dockerfile.v0
<missing> 36 seconds ago EXPOSE map[22/tcp:{}] 0B buildkit.dockerfile.v0
<missing> 36 seconds ago RUN /bin/sh -c echo "root:huawei" | chpasswd... 1.77kB buildkit.dockerfile.v0
......
测试
bash
[root@docker ~]# docker run -d -p 2022:22 --name sshtest centos:ssh
73d963d15407a1e73097540bb320b9edf05b468001bd707abf01bc7be5e54bcb
[root@docker ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
73d963d15407 centos:ssh "/usr/sbin/sshd -D" 6 seconds ago Up 5 seconds 0.0.0.0:2022->22/tcp, :::2022->22/tcp sshtest
[root@docker ~]# ssh root@localhost -p 2022
The authenticity of host '[localhost]:2022 ([::1]:2022)' can't be established.
ECDSA key fingerprint is SHA256:z1owYLOuClnbPrZwXxgy1jcItQT1k+QX6LxosydT64A.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[localhost]:2022' (ECDSA) to the list of known hosts.
root@localhost's password:
"System is booting up. Unprivileged users are not permitted to log in yet. Please come back later. For technical details, see pam_nologin(8)."
[root@73d963d15407 ~]#
案例2:自定义httpd镜像
创建dockerfile
bash
[root@docker ~]# vim httpd.dockerfile
FROM centos:8.4.2105
RUN minorver=8.4.2105 \
&& sed -e "s|^mirrorlist=|#mirrorlist=|g" -e "s|^#baseurl=http://mirror.centos.org/\$contentdir/\$releasever|baseurl=https://mirrors.aliyun.com/centos-vault/$minorver|g" -i.bak /etc/yum.repos.d/CentOS-*.repo
RUN yum install -y httpd && yum clean all && rm -rf /var/cache/yum
COPY index.html /var/www/html/
EXPOSE 80
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
[root@docker ~]# echo Hello World > index.html
构建镜像
bash
[root@docker ~]# docker build -t httpd:centos -f httpd.dockerfile .
查看现象
bash
[root@docker ~]# docker history httpd:centos
测试
bash
[root@docker ~]# docker run -d -p 80:80 --name myweb httpd:centos
1e0b0631cf708bcc0a162d56b936a12cd06c9bcdebcc2594b23c2fbee3ed8894
[root@docker ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e0b0631cf70 httpd:centos "/usr/sbin/httpd -DF..." About a minute ago Up About a minute 0.0.0.0:80->80/tcp, :::80->80/tcp myweb
[root@docker ~]# curl localhost
Hello World
镜像命名
镜像的名字由两部分组成:repository 和 tag。
[image name] = [repository]:[tag]
如果执行 docker build 时没有指定 tag,会使用默认值 latest,相当于:
docker build -t ubuntu-with-vim:latest
tag 使用
每个 repository 可以有多个 tag,而多个 tag 可能对应的是同一个镜像。
docker tag 给镜像打 tag
bash
docker tag myimage-v1.9.1 myimage:1
docker tag myimage-v1.9.1 myimage:1.9
docker tag myimage-v1.9.1 myimage:1.9.1
docker tag myimage-v1.9.1 myimage:latest
公共仓库-dockerhub
Docker仓库是Docker集中存放镜像文件的场所;仓库存放着很多类镜像,每类镜像包括多个镜像文件,通过不同的标签(tag)来进行区分。
使用公共仓库-华为云
操作流程:




复制登录指令,回到docker上登陆
bash
[root@docker ~]# docker login -u cn-east-3@HST3WGZY13FUUTQ9ZC32 -p b8e7d74da04a90cb0b1ac08ff894cebe6a8fc039f494dedd08cbc64095761aab swr.cn-east-3.myhuaweicloud.com
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
上传镜像
格式
bash
docker tag {镜像名称}:{版本名称} swr.cn-east-3.myhuaweicloud.com/{组织名称}/{镜像名称}:{版本名称}
docker push swr.cn-east-3.myhuaweicloud.com/{组织名称}/{镜像名称}:{版本名称}
例:
bash
[root@docker ~]# docker images httpd:centos
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd centos 973cac3a687f 4 hours ago 288MB
[root@docker ~]# docker tag httpd:centos swr.cn-east-3.myhuaweicloud.com/stj/centos_httpd:v1
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd centos 973cac3a687f 4 hours ago 288MB
swr.cn-east-3.myhuaweicloud.com/stj/centos_httpd v1 973cac3a687f 4 hours ago 288MB
[root@docker ~]# docker push swr.cn-east-3.myhuaweicloud.com/stj/centos_httpd:v1
The push refers to repository [swr.cn-east-3.myhuaweicloud.com/gaoqiaodong/centos_httpd]
63f254ce601f: Pushed
ca98143f89dc: Pushed
7d3485567b78: Pushed
717a93ee4ccf: Pushed
74ddd0ec08fa: Layer already exists
v1: digest: sha256:49c69273c49ab25e17ad54d2bb74412ae09a699dc3ee91f72c1cef9ba8ce405e size: 1363
搭建本地仓库
Registry
启动 registry 容器。
shell
[root@docker ~]# docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:2
-d 是后台启动容器
-p 将容器的 5000 端口映射到 Host 的 5000 端口,5000 是 registry 服务端口
-v 将容器 /var/lib/registry 目录映射到 Host 的 /myregistry,用于存放镜像数据
docker tag 重命名镜像
bash
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd latest 5daf6a4bfe74 2 months ago 148MB
[root@docker ~]# docker tag httpd:latest localhost:5000/httpd:v1
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd latest 5daf6a4bfe74 2 months ago 148MB
localhost:5000/httpd v1 5daf6a4bfe74 2 months ago 148MB
repository 的完整格式为:[registry-host]:[port]/[username]/xxx
只有 Docker Hub 上的镜像可以省略 [registry-host]:[port]
上传镜像。
bash
[root@docker ~]# docker push localhost:5000/httpd:v1
......
[root@docker httpd]# curl http://localhost:5000/v2/_catalog
{"repositories":["httpd"]}
企业级私有仓库 Harbor
Harbor 是构建企业级私有docker镜像的仓库的开源解决方案,它是Docker Registry的更高级封装,除了提供友好的Web UI界面,角色和用户权限管理,用户操作审计等功能外,它还整合了K8s的插件(Add-ons)仓库。
harbor下载:https://github.com/goharbor/harbor/releases
下载
bash
[root@docker ~]# wget https://github.com/goharbor/harbor/releases/download/v2.9.1/harbor-offline-installer-v2.9.1.tgz
[root@docker ~]# tar -xvf harbor-offline-installer-v2.9.1.tgz
导入 Harbor 镜像
bash
[root@docker ~]# mkdir /opt/harbor
[root@docker ~]# mv harbor/* /opt/harbor/
[root@docker ~]# cd /opt/harbor/
[root@docker harbor]# docker load -i harbor.v2.9.1.tar.gz
修改 Harbor 配置文件
bash
[root@docker harbor]# cp -ar harbor.yml.tmpl harbor.yml
[root@docker harbor]# vim harbor.yml

hostname:设置 IP
https: # 注释掉
harbor_admin_password: harbor 登录密码
更新并安装
bash
[root@docker harbor]# ./prepare
[root@docker harbor]# ./install.sh
登录WEB界面

使用
按照步骤将一个镜像推送到 Harbor 中:
在用户管理中创建名称为 images_admin 的用户:

在项目中创建名称为cloud的项目,并添加 images_admin 为项目管理员


将内网服务器 IP 和端口配置到 daemon.json 文件中
bash
[root@docker ~]# vim /etc/docker/daemon.json
{
"insecure-registries": ["192.168.108.30"],
"registry-mirrors": [ "https://054b8ac70e8010d90f2ac00ef29e6580.mirror.swr.myhuaweicloud.com" ]
}
# 重启安装
[root@docker ~]# systemctl restart docker
[root@docker harbor]# ./install.sh
登录服务器
bash
[root@docker ~]# docker login 192.168.108.30
登录后家目录下会有一个.docker文件夹
bash
[root@docker ~]# cd ~/.docker/
[root@docker .docker]# cat config.json
{
"auths": {
"192.168.108.30": {
"auth": "aW1hZ2VzX2FkbWluOkNsb3VkMTIjJA=="
},
"swr.cn-north-4.myhuaweicloud.com": {
"auth": "Y24tbm9ydGgtNEBMUVhBVjU4MENES1A3SUoxTDREMzpmM2NlMTJlODY4ODVkN2JkZWZlYmFiMWI1N2RmZDBiYjJiM2MxZTEyNjUxYWQ1ZTk1ODY1Nzg4MTczYzI4OTJj"
}
}
}
上传镜像
bash
[root@docker .docker]# docker tag nginx:latest 192.168.108.30/cloud/nginx:latest
[root@docker .docker]# docker push 192.168.108.30/cloud/nginx:latest
下载镜像


bash
[root@docker .docker]# docker pull 192.168.108.30/cloud/nginx
卸载harbor
bash
[root@docker ~]# cd /opt/harbor/
[root@docker harbor]# docker compose down
......
# 清理镜像
[root@docker harbor]# docker images |grep harbor|awk '{print $1":"$2}' | xargs docker rmi
# 清理harbor使用的目录,由prepare脚本定义
[root@docker harbor]# rm -rf /data
删除软件包
bash
[root@docker opt]# cd
[root@docker ~]# ls
anaconda-ks.cfg harbor harbor-offline-installer-v2.9.1.tgz
[root@docker ~]# rm -f harbor-offline-installer-v2.9.1.tgz
[root@docker ~]# rm -rf /opt/harbor/
Docker镜像小结
images 显示镜像列表
history 显示镜像构建历史
commit 从容器创建新镜像
build 从 Dockerfile 构建镜像
tag 给镜像打 tag
pull 从 registry 下载镜像
push 将 镜像 上传到 registry
rmi 删除 Docker host 中的镜像
search 搜索 Docker Hub 中的镜像
保存本地镜像为文件-save
docker默认使用overlay2存储驱动存储镜像,镜像存储在本地/var/lib/docker/overlay2
bash
[root@docker ~]# docker info | grep 'Storage Driver'
Storage Driver: overlay2
示例:
bash
# 将 httpd 镜像保存为 httpd.tar
[root@docker ~]# docker save httpd -o httpd.tar
[root@docker ~]# ls
httpd.tar
将本地镜像文件导入本地-load
示例:
bash
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
[root@docker ~]# docker load -i httpd.tar
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd latest 90f191b9781e 11 days ago 148MB
说明:如果本地镜像名与导入的镜像重名,则本地的镜像会被覆盖。
bash
[root@docker ~]# docker rm -f $(docker ps -aq) #删除所有容器
[root@docker ~]# docker rmi -f $(docker images -aq) #删除所有镜像
容器
什么是容器
容器是一种轻量级、可移植、自包含的软件打包技术,使应用程序可以在几乎任何地方以相同的方式运行。容器无需任何修改就能够在生产系统的虚拟机、物理服务器或公有云主机上运行。
容器与虚拟机
容器由两部分组成:
- 应用程序本身
- 依赖:比如应用程序需要的库或其他软件
容器在 Host 操作系统的用户空间中运行,与操作系统的其他进程隔离。这一点显著区别于的虚拟机。
下图展示了二者的区别:

| 容器 | 虚拟机 | |
|---|---|---|
| 启动速度 | 秒甚至毫秒启动 | 数秒至数十秒 |
| 系统内核 | 共享内核 | 不共享内核 |
| 实现技术 | 利用Linux内核技术Namespace/Cgroup等实现。 | 依赖虚拟化技术实现,由Hypervisor层实现对资源的隔离 |
| 隔离效果 | 进程级别的隔离 | 系统资源级别的隔离 |
| 资源消耗(性能) | 容器中的应用只是宿主机上的一个普通进程 | 使用虚拟化技术,就会有额外的资源消耗和占用 |
| 资源调用 (敏捷性) | 应用进程直接由宿主机OS管理 | 应用进程需经过Hypervisor的拦截和处理,才能调用系统资源 |
| 运行数量 | 一台服务器上能启动1000+容器 | 一台服务器上一般不超过100台虚拟机 |
| 应用 | DevOps、微服务等 | 用于硬件资源划分 |
| 镜像 | 分层镜像 | 非分层镜像 |
如图所示,由于所有的容器共享同一个 Host OS,这使得容器在体积上要比虚拟机小很多。另外,启动容器不需要启动整个操作系统,所以容器部署和启动速度更快,开销更小,也更容易迁移。
容器的作用
容器使软件具备了超强的可移植能力。
- 容器解决的问题
Docker 将集装箱思想运用到软件打包上,为代码提供了一个基于容器的标准化运输系统。
Docker 可以将任何应用及其依赖打包成一个轻量级、可移植、自包含的容器。容器可以运行在几乎所有的操作系统上。
-
容器的优势
-
对于开发人员 :容器意味着环境隔离和可重复性。开发人员只需为应用创建一次运行环境,然后打包成容器便可在其他机器上运行。另外,容器环境与所在的 Host 环境是隔离的,就像虚拟机一样,但更快更简单。
-
对于运维人员:只需要配置好标准的 runtime 环境,服务器就可以运行任何容器。这使得运维人员的工作变得更高效,一致和可重复。容器消除了开发、测试、生产环境的不一致性。
-
运行容器
-
指定容器的三种方法:
- 短ID
- 长ID
- 容器名称,可通过
--name为容器命名;重命名容器可执行docker rename
-
容器按用途可分为两类:
- 服务类容器
- 工具类容器
docker run=docker create + docker start
docker run 是启动容器的方法,可用三种方式指定容器启动时执行的命令:
- CMD 指令。
- ENTRYPOINT 指令。
- 在
docker run命令行中指定。
让容器长期运行
bash
[root@docker ~]# docker run ubuntu /bin/bash -c "while true ; do sleep 1 ; echo hahaha; done"
-d以后台方式启动容器
bash
[root@docker ~]# docker run -d ubuntu /bin/bash -c "while true ; do sleep 1 ; echo hahaha; done"
2a0bfa267fe146753b4fc8b23d55b08fbe3a5f9b5e093de6885133f6bbd20c56
通过 "长ID"、"短ID" 或者 "名称" 来指定要操作的容器:
bash
[root@docker ~]# docker stop 081be2bc2e1d
081be2bc2e1d
进入容器
- 有两种方法进入容器:attach 和 exec
docker attach
通过 docker attach 可以 attach 到容器启动命令的终端
bash
[root@docker ~]# docker run -d ubuntu /bin/bash -c "while true ; do sleep 1 ; echo I_am_in_container ; done"
dc508b94447f83b46080267580607569a187fcc7f780433f646e9d66949731a6
[root@docker ~]# docker attach dc508b94447f83b46080267580607569a187fcc7f780433f646e9d66949731a6
I_am_in_container
I_am_in_container
注:可通过 Ctrl+p 然后 Ctrl+q 组合键退出 attach 终端
docker exec
通过 docker exec 进入相同的容器:

-
-it以交互模式打开一个 bash 终端 -
执行
exit退出容器,回到 docker host -
docker exec -it <container> bash|sh是执行 exec 最常用的方式
attach 与 exec 区别
- attach 直接进入容器 启动命令 的终端,不会启动新的进程
- exec 则是在容器中打开新的终端,并且可以启动新的进程
- 如果想直接在终端中查看启动命令的输出,用 attach;其他情况使用 exec
如果只是为了查看启动命令的输出,可以使用 docker logs 命令:
bash
[root@docker ~]# docker logs -f dc508b94447f
I_am_in_container
I_am_in_container
I_am_in_container
限制容器对内存的使用
docker 通过 cgroup 来控制容器使用的资源配额,包括 CPU、内存、磁盘三大方面,基本覆盖了常见的资源配额和使用量控制。
可以使用 stress 工具来测试 CPU 和内存
使用 Dockerfile 创建一个基于 Ubuntu 的 stress 工具镜像
bash
[root@docker dockerfile]# vim Dockerfile
FROM ubuntu
RUN apt-get -y update && apt-get -y install stress
ENTRYPOINT ["/usr/bin/stress"] # 以服务或进程的形式运行
[root@docker ~]# docker build -t ubuntu-with-stress .
内存限额
容器可使用的内存包括两部分:物理内存 和 swap
-m或--memory:设置内存的使用限额--memory-swap:设置 内存+swap 的使用限额
docker run -m 200M --memory-swap=300M ubuntu
其含义是允许该容器最多使用 200M 的内存和 100M 的 swap
如果--memory-swap 设置为0 或者不设置,则容器可以使用的swap大小为-m值的两倍。
如果 --memory-swap 的值和-m 值相同,则容器不能使用swap
如果 --memory-swap值为-1。它表示容器程序使用的内存受限,而可以使用的swap空间不受限制(宿主机有多少swap空间该容器就可以使用多少)
压力测试
bash
[root@docker ~]# docker run -it -m 200M --memory-swap=300M ubuntu-with-stress --vm 1 --vm-bytes 280M -v
-
--vm 1:启动 1 个内存工作线程 -
--vm-bytes 280M:每个线程分配 280M 内存
限制容器对CPU的使用
Docker 可以通过 -c 或 --cpu-shares 设置容器使用 CPU 的权重;如果不指定,默认值为 1024
--cpu-shares 的值不能保证可以获得1个 vcpu 或者多少 GHz 的 CPU 资源,仅仅只是一个弹性的加权值
注:这种按权重分配 CPU 只会发生在 CPU 资源紧张的情况下
启动 container_A,cpu share 为 1024
bash
[root@docker ~]# docker run --name "container_A" -it -c 1024 ubuntu-with-stress --cpu 4 -v
--cpu用来设置工作线程的数量
启动 container_B,cpu share 为 512
bash
[root@docker ~]# docker run --name "container_B" -it -c 512 ubuntu-with-stress --cpu 4 -v
查看容器对 CPU 的使用情况

容器的导入导出
export-导出容器
- 不管容器是否处于运行状态,都可以导出为文件
bash
[root@docker ~]# docker run -d --name httpd1 httpd
e4f0a329c4df50ef0afb0bf21e22edc20e5a24c03ae64c6340aa2992d6e32525
[root@docker ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e4f0a329c4df httpd "httpd-foreground" 3 minutes ago Up 3 minutes 80/tcp httpd1
[root@docker ~]# docker export httpd1 -o myhttpd.tar
[root@docker ~]# ls
myhttpd.tar
import-导入容器
bash
[root@docker ~]# docker import myhttpd.tar
sha256:9ae4699fa217a7240c73a50e93a8c1d359d22cf60869d350c8aab8b3c02aabcf
[root@docker ~]# docker import myhttpd.tar myweb:v1
sha256:9fcb90561d2014130ef19f9dd8af5efd7a0a4a2154907bc818ac6b887f13755c
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
myweb v1 9fcb90561d20 3 seconds ago 146MB
<none> <none> 9ae4699fa217 32 seconds ago 146MB
docker save和docker export对比:
docker save:将镜像保存为文件,save会保存该镜像的所有元数据和历史记录。docker export:将容器导出为文件,文件会丢失所有元数据和历史记录,仅保存容器当时的状态,再次导入会当作全新的镜像。
网络
none、host和bridge网络
Docker 安装时会自动在 host 上创建三个网络,我们可用 docker network ls 命令查看:
bash
[root@docker ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
a1b809382f0d bridge bridge local
6ad21ed9ea1f host host local
4e31521b27c6 none null local
none 网络
挂在none网络上的容器只有lo,无法与外界通信

容器创建时,可以通过
--network=none指定使用 none 网络
bash
[root@docker ~]# docker run -it --network=none busybox
/ # 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)
一些对安全性要求高并且不需要联网的应用可以使用 none 网络
host 网络
连接到 host 网络的容器共享 Docker host 的网络栈,容器的网络配置与 host 完全一样
通过
--network=host指定使用 host 网络
bash
[root@docker ~]# docker run -it --network=host busybox
/ # ip l
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq qlen 1000
link/ether 00:0c:29:33:15:f6 brd ff:ff:ff:ff:ff:ff
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue
link/ether 02:42:02:fd:82:b3 brd ff:ff:ff:ff:ff:ff
/ #
/ # hostname #容器主机与宿主机相同
docker
/ #
如果容器对网络传输效率有较高要求,则可以选择 host 网络
brige 网络
Docker 安装时会创建一个 命名为 docker0 的 linux bridge,实际上它是 Linux 的一个 bridge (网桥),可以理解为一个软件交换机,它会在挂载到它的网口之间进行转发。如果不指定--network,创建的容器默认都会挂到 docker0 上。
当创建一个 Docker 容器的时候,同时会创建了一对 veth pair 接口,通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。

配置yum源,安装软件
bash
[root@docker ~]# cd /etc/yum.repos.d/
[root@docker yum.repos.d]# vim cloud.repo
[centos-openstack-victoria]
name=CentOS 8 - OpenStack victoria
baseurl=https://mirrors.aliyun.com/centos-vault/8-stream/cloud/x86_64/openstack-victoria/
enabled=1
gpgcheck=0
[root@docker yum.repos.d]# yum install -y bridge-utils
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02420be905a5 no
创建容器查看变化
bash
[root@docker ~]# docker run -itd --name busybox1 busybox
5225d246f751dbfc4cdf745675d9c79d3de1b91dd4174268c35e671b9f1b0c80
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02420be905a5 no vethddb2744
一个新的网络接口 vethddb2744 被挂到了 docker0 上,vethddb2744就是新创建容器的虚拟网卡
查看容器的网络配置
bash
[root@docker ~]# docker exec -it busybox1 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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
# 容器里的网卡是24号网卡名字叫eth0,对面是25号网卡
24: eth0@if25: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever

自定义容器网络
用户可以根据业务需要创建 user-defined 网络
我们可通过 bridge 驱动创建类似前面默认的 bridge 网络,例如:
bash
[root@docker ~]# docker network create --driver bridge my_net
89f7bc11b602e84452ae01786113ac196a535f7296b9989ad941b3a48a5e6d04
查看当前 host 的网络
bash
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-89f7bc11b602 8000.0242194d039e no
docker0 8000.02420be905a5 no vethddb2744
执行 docker network inspect 查看一下 my_net 的配置信息:
bash
[root@docker ~]# docker network inspect my_net
......
"Subnet": "172.18.0.0/16",
"Gateway": "172.18.0.1"
......
这里 172.18.0.0/16 是 Docker 自动分配的 IP 网段
创建网段时指定
--subnet和--gateway参数
bash
[root@docker ~]# docker network create --driver bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my_net2
ec761bc51778f67c2245af72fd969f00cd517ee617a10a70dc01904f9c10279d
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-89f7bc11b602 8000.0242194d039e no
br-ec761bc51778 8000.02427fa54b88 no
docker0 8000.02420be905a5 no vethddb2744
[root@docker ~]# docker network inspect my_net2
.......
通过
--network指定容器要使用的网络:
bash
[root@docker ~]# docker run -it --network=my_net2 --name busybox2 busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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
28: eth0@if29: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:16:10:02 brd ff:ff:ff:ff:ff:ff
inet 172.22.16.2/24 brd 172.22.16.255 scope global eth0
valid_lft forever preferred_lft forever
/ # ctrl+P,ctrl+q退出容器
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-89f7bc11b602 8000.0242194d039e no
br-ec761bc51778 8000.02427fa54b88 no veth02dd704
docker0 8000.02420be905a5 no vethddb2744
通过
--ip指定容器的 IP
bash
[root@docker ~]# docker run -it --network=my_net2 --ip 172.22.16.8 --name busybox3 busybox
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-89f7bc11b602 8000.0242194d039e no
br-ec761bc51778 8000.02427fa54b88 no veth02dd704
veth5fbb7f6
docker0 8000.02420be905a5 no vethddb2744
注:只有使用 --subnet 创建的网络才能指定静态 IP。

容器之间的连通性
同一网络中的容器、网关之间都是可以通信
busybox2 ping busybox3
bash
[root@docker ~]# docker exec -it busybox2 sh
/ # ping -c 3 172.22.16.8
PING 172.22.16.8 (172.22.16.8): 56 data bytes
64 bytes from 172.22.16.8: seq=0 ttl=64 time=0.197 ms
64 bytes from 172.22.16.8: seq=1 ttl=64 time=0.137 ms
64 bytes from 172.22.16.8: seq=2 ttl=64 time=0.158 ms
--- 172.22.16.8 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.137/0.164/0.197 ms
# ping my_net2网关地址
/ # ping -c 3 172.22.16.1
PING 172.22.16.1 (172.22.16.1): 56 data bytes
64 bytes from 172.22.16.1: seq=0 ttl=64 time=0.149 ms
64 bytes from 172.22.16.1: seq=1 ttl=64 time=0.116 ms
64 bytes from 172.22.16.1: seq=2 ttl=64 time=0.182 ms
--- 172.22.16.1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.116/0.149/0.182 ms
通过
docker network connect为 busybox1 容器添加一块 my_net2的网卡
bash
[root@docker ~]# docker network connect my_net2 busybox1
验证 busybox1 ping通 busybox2,3
bash
[root@docker ~]# docker exec -it busybox2 sh
/ # ping -c 3 172.22.16.3
PING 172.22.16.3 (172.22.16.3): 56 data bytes
64 bytes from 172.22.16.3: seq=0 ttl=64 time=0.199 ms
64 bytes from 172.22.16.3: seq=1 ttl=64 time=0.134 ms
64 bytes from 172.22.16.3: seq=2 ttl=64 time=0.141 ms
--- 172.22.16.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.134/0.158/0.199 ms

容器通信的三种方式
容器之间可通过 IP 、Docker DNS Server 、 joined 容器三种方式通信
只能在 user-defined 网络中使用 docker DNS
joined 容器 可以使两个或多个容器共享一个网络栈,共享网卡和配置信息,joined 容器之间可以通过 127.0.0.1 直接通信。
通过
--network=container:web1指定 jointed 容器为 web1
bash
[root@docker ~]# docker run -it --network container:web1 busybox
busybox 和 web1 的网卡 mac 地址与 IP 完全一样,它们共享了相同的网络栈;busybox 可以直接用 127.0.0.1 访问 web1 的 http 服务。
容器与外部世界
容器访问外部世界
容器默认就能访问外网
bash
[root@docker ~]# docker run -it --name test1 busybox
/ # ping -c 3 www.baidu.com
PING www.baidu.com (223.109.82.6): 56 data bytes
64 bytes from 223.109.82.6: seq=0 ttl=127 time=21.240 ms
64 bytes from 223.109.82.6: seq=1 ttl=127 time=14.987 ms
64 bytes from 223.109.82.6: seq=2 ttl=127 time=14.651 ms
--- www.baidu.com ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 14.651/16.959/21.240 ms
注:这里外网指的是容器网络以外的网络环境,并非特指 internet
通过 NAT,docker 实现了容器对外网的访问
外部世界访问容器
docker 可将容器对外提供服务的端口映射到 host 的某个端口,外网通过该端口访问容器
通过 docker ps 或者 docker port 查看到 host 映射的端口
将 80 端口映射到 host 的 8080 端口
bash
[root@docker ~]# docker run -d -p 8080:80 httpd
25b04cb7f6d6c012c609251a425475fcf7da03c93feb20c1d951eb45cb1ef79b
[root@docker ~]#
[root@docker ~]# curl 192.168.108.30:8080
<html><body><h1>It works!</h1></body></html>
存储
Docker 为容器提供了两种存放数据的资源:
- 由 storage driver 管理的镜像层和容器层
- Data Volume
storage driver
storage driver 实现了多层数据的堆叠并为用户提供一个单一的合并之后的统一视图
优先使用 Linux 发行版默认的 storage driver。
运行docker info查看CentOS的默认 driver:
bash
[root@docker ~]# docker info
Data Volume
Data Volume 本质上是 Docker Host 文件系统中的目录或文件,能够直接被 mount 到容器的文件系统中
特点:
- Data Volume 是目录或文件,而非没有格式化的磁盘(块设备)
- 容器可以读写 volume 中的数据
- volume 数据可以被永久的保存,即使使用它的容器已经销毁
bind mount
bind mount 是将 host 上已存在的目录或文件 mount 到容器
bash
[root@docker ~]# mkdir htdocs
[root@docker ~]# cd htdocs/
[root@docker htdocs]# touch index.html
[root@docker htdocs]# vim index.html
<html><body><h1>This is a file in host file system !</h1></body></html>
[root@docker ~]# cat htdocs/index.html
<html><body><h1>This is a file in host file system !</h1></body></html>
通过
-v将其 mount 到 httpd 容器
bash
[root@docker ~]# docker run -d -p 80:80 -v ~/htdocs:/usr/local/apache2/htdocs httpd
883f8a22b2be796928d16ad131f6cba922492e325fdadf4275ca9f59eae5ed12
-v的格式为<host path>:<container path>
bind mount 时还可以指定数据的读写权限,默认是可读可写
bash
# ro 设置只读权限
[root@docker ~]# docker run -d -p 80:80 -v ~/htdocs:/usr/local/apache2/htdocs:ro httpd
bf1f526ddde7a7babb29adc091eef039628ba2eb288e6db33c9ccd946cc5d5f1
[root@docker ~]# docker exec -it bf1f526ddde7 bash
root@bf1f526ddde7:/usr/local/apache2# echo "do some changes" > htdocs/index.html
bash: htdocs/index.html: Read-only file system
只 mount 文件
bash
[root@docker ~]# docker run -d -p 80:80 -v ~/htdocs/index.html:/usr/local/apache2/htdocs/new_index.html httpd
643e8820e98a17b977a984903ddfa6f37dcae3d705d45b624d0fce5c94fecb0c
[root@docker ~]#
[root@docker ~]# curl 127.0.0.1:80
<html><body><h1>It works!</h1></body></html>
[root@docker ~]#
[root@docker ~]# curl 127.0.0.1:80/new_index.html
updated index page!
[root@docker ~]#
docker managed volume
docker managed volume 不需要指定 mount 源,只要指明 mount point
bash
[root@docker ~]# docker run -d -p 80:80 -v /usr/local/apache2/htdocs httpd
c75f36c4bf32e39f2d078d41956be85522c0630cf91498123dcd83ba159ce873
查看容器data volume
bash
[root@docker ~]# docker inspect c75f36c4bf32
...
"Mounts": [
{
"Type": "volume",
"Name": "1cc915096121dea197bbbb93fc90e6491d530e0c9e2ace1de07e2a635e569d16",
"Source": "/var/lib/docker/volumes/1cc915096121dea197bbbb93fc90e6491d530e0c9e2ace1de07e2a635e569d16/_data",
"Destination": "/usr/local/apache2/htdocs",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
...
Source 就是该 volume 在 host 上的目录,每当容器申请 mount docker manged volume 时,docker 都会在/var/lib/docker/volumes 下生成一个目录,这个目录就是 mount 源
除了通过 docker inspect 查看 volume,我们也可以用 docker volume 命令:
bash
[root@docker ~]# docker volume ls
DRIVER VOLUME NAME
local 1cc915096121dea197bbbb93fc90e6491d530e0c9e2ace1de07e2a635e569d16
[root@docker ~]#
[root@docker ~]# docker volume inspect 1cc915096121dea197bbbb93fc90e6491d530e0c9e2ace1de07e2a635e569d16
[
{
"CreatedAt": "2024-09-17T21:04:33+08:00",
"Driver": "local",
"Labels": {
"com.docker.volume.anonymous": ""
},
"Mountpoint": "/var/lib/docker/volumes/1cc915096121dea197bbbb93fc90e6491d530e0c9e2ace1de07e2a635e569d16/_da
"Name": "1cc915096121dea197bbbb93fc90e6491d530e0c9e2ace1de07e2a635e569d16",
"Options": null,
"Scope": "local"
}
]
共享数据
容器与 host 共享数据
docker cp 可以在容器和 host 之间拷贝数据,也可以直接通过 Linux 的 cp 命令复制到 /var/lib/docker/volumes/xxx
bash
[root@docker ~]# docker run -d -p 80:80 -v /usr/local/apache2/htdocs httpd
889b9d5309bd12499f8e4ee78a491d9ba7acef5660be00f30cda6569c9974c6f
[root@docker ~]# curl 127.0.0.1:80
<html><body><h1>It works!</h1></body></html>
[root@docker ~]# docker cp ~/htdocs/index.html 889b9d5309bd:/usr/local/apache2/htdocs
Successfully copied 2.05kB to 889b9d5309bd:/usr/local/apache2/htdocs
[root@docker ~]# curl 127.0.0.1:80
updated index page!
容器之间共享数据
方法一:将共享数据放在 bind mount 中,然后将其 mount 到多个容器
方法二:使用 volume container
volume container 是专门为其他容器提供 volume 的容器
它提供的卷可以是 bind mount,也可以是 docker managed volume
bash
[root@docker ~]# docker create --name vc_data \
-v ~/htdocs/:/usr/local/apache2/htdocs \
-v /other/userful/tools \
busybox
bb4a33bf34aa7817ea752db83079aff15a5dfd77c23363f2e8dd3096d1cb910f
注 :这里执行的是 docker create 命令,因为 volume container 的作用只是提供数据,它本身不需要处于运行状态
容器 mount 了两个 volume:
- bind mount,存放 web server 的静态文件
- docker managed volume,存放一些实用工具
通过 --volumes-from 使用 vc_data 这个 volume container
bash
[root@docker ~]# docker run --name web1 -d -p 80 --volumes-from vc_data httpd
362f039b562e4bf0020c38839a69bfd62733f27fda5481eb5b58178f41318ffe
volume生命周期管理
备份
所有的本地镜像都存在 host 的 /myregistry 目录中,我们要做的就是定期备份这个目录
恢复
volume 的恢复也很简单,如果数据损坏了,直接用之前备份的数据拷贝到 /myregistry 就可以了
迁移
使用更新版本的 Registry,这就涉及到数据迁移:
-
docker stop当前 Registry 容器。 -
启动新版本容器并 mount 原有 volume。
docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:latest
当然,在启用新容器前要确保新版本的默认数据路径是否发生变化。
销毁
docker 不会销毁 bind mount,删除数据的工作只能由 host 负责。对于 docker managed volume,在执行 docker rm 删除容器时可以带上 -v 参数,docker 会将容器使用到的 volume 一并删除,但前提是没有其他容器 mount 该 volume,目的是保护数据
如果想批量删除孤儿 volume,可以执行:
docker volume rm $(docker volume ls -q)
容器监控
ps
bash
[root@docker ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9f8bc2c3a5c7 nginx "/docker-entrypoint...." 3 seconds ago Up 2 seconds 80/tcp sad_faraday
1e0b0631cf70 httpd:centos "/bin/sh -c '/usr/sb..." 23 minutes ago Up 23 minutes 0.0.0.0:80->80/tcp, :::80->80/tcp myweb
4b78f371fc06 centos:ssh "/usr/sbin/sshd -D" 32 minutes ago Up 32 minutes 0.0.0.0:2022->22/tcp, :::2022->22/tcp sshtest
top
bash
[root@docker ~]# docker top sshtest #sshtest是容器名
UID PID PPID C STIME TTY TIME CMD
root 5220 5198 0 21:31 ? 00:00:00 /usr/sbin/sshd -D
bash
[root@docker ~]# docker top sshtest -au
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 5220 0.0 0.0 76532 7080 ? Ss 21:31 0:00 /usr/sbin/sshd -D
stats
列出容器资源使用率
bash
[root@docker ~]# docker stats
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
9f8bc2c3a5c7 sad_faraday 0.00% 5.141MiB / 15.36GiB 0.03% 866B / 0B 8.19kB / 26.6kB 5
1e0b0631cf70 myweb 0.06% 38.39MiB / 15.36GiB 0.24% 1.64kB / 609B 0B / 0B 213
4b78f371fc06 sshtest 0.00% 2.258MiB / 15.36GiB 0.01% 9.7kB / 7.99kB 8.19kB / 23.6kB 1
容器日志
docker logs 命令查看容器日志
bash
[root@docker ~]# docker logs a8286845e6f8
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3. Set the 'ServerName' directive globally to suppress this message
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3. Set the 'ServerName' directive globally to suppress this message
[Tue Oct 08 14:28:33.168712 2024] [mpm_event:notice] [pid 1:tid 1] AH00489: Apache/2.4.62 (Unix) configured -- resuming normal operations
[Tue Oct 08 14:28:33.168801 2024] [core:notice] [pid 1:tid 1] AH00094: Command line: 'httpd -D FOREGROUND'
.......
-f参数可以继续打印出新日志
docker图形界面管理
DockerUI 容器管理器的安装与使用
简介:
DockerUI是一个易用且轻量化的 Docker 管理工具,通过 Web 界面的操作,更方便对于 Docker 指令不熟悉的用户更容易操作 Docker 。
功能:
- Docker主机管理:数据卷管理,镜像管理,容器管理,构建管理,仓库配置管理,网络配置管理
- Docker Swarm集群管理:集群概要信息,节点管理,Service管理,任务管理,密码管理,配置管理
安装
启动容器并映射8999端口
bash
[root@docker ~]# docker run -d --name docker.ui --restart always -v /var/run/docker.sock:/var/run/docker.sock -p 8999:8999 joinsunsoft/docker.ui
7af59b5074732e4bd7cb9ca532379ddc35f52cbbc6aa653bda67954e56ce8d3e

Docker 图形化界面管理工具 Portainer
Portainer 是一个 Docker 图形化管理工具,可以通过 Web UI 轻松的管理容器、镜像、网络、卷
安装
创建存储卷
bash
[root@docker ~]# docker volume create portainer_data
portainer_data
通过docker安装Portainer
bash
[root@docker ~]# docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest
bd0967eedcae7fddbe5217bafcac7761c6a2d6f430e4b80bf5f4a9551567a828
9443 端口默认会启用 SSL,如果需要直接通过 http 访问,需要加上 -p 9000:9000 访问 9000 端口
-v /var/run/docker.sock:/var/run/docker.sock参数使得Portainer能够访问Docker守护进程,从而能够管理容器
-v portainer_data:/data参数则用于持久化Portainer的数据
访问
