Docker 容器技术
一、容器技术概述
1、为什么要学习 Docker?
容器技术是继大数据、云计算之后又一项炙手可热的技术。对 IT 从业者来说,掌握容器技术既是市场需求,也是提升自我价值的重要途径。
Docker 是当前最流行的容器技术代表,Google Trends 中 Docker 的搜索热度持续上升。
学习容器技术可以按照 3W 框架 进行:
- What:容器是什么?
- Why:为什么需要容器?
- How:如何使用容器?
2、什么是容器?
容器是一种轻量级、可移植、自包含的软件打包技术,使应用程序可以在几乎任何地方以相同的方式运行。
容器由两部分组成:
- 应用程序本身;
- 依赖:比如应用程序需要的库或其他软件。
容器在 Host 操作系统的用户空间中运行,与操作系统的其他进程隔离。
3、容器与虚拟机的区别
| 特性 | 容器 | 虚拟机 |
|---|---|---|
| 启动速度 | 秒级甚至毫秒级 | 数秒至数十秒 |
| 系统内核 | 共享内核 | 不共享内核 |
| 实现技术 | Namespace/Cgroup | Hypervisor |
| 隔离效果 | 进程级别隔离 | 系统资源级别隔离 |
| 资源消耗 | 容器只是宿主机上的普通进程 | 有额外资源消耗 |
| 运行数量 | 单机可启动 1000+ 容器 | 一般不超过 100 台 |
| 镜像 | 分层镜像 | 非分层镜像 |
| 迁移性 | 优秀 | 一般 |
4、为什么需要容器?
核心答案:容器使软件具备了超强的可移植能力。
传统开发面临的问题:
- 应用包含多种服务,每个服务依赖不同的库和软件包;
- 部署环境多样:开发 VM、QA 服务器、公有云、私有云、生产集群等。
容器借鉴了"集装箱"思想:任何货物都放进标准集装箱,运输过程无需打开,到达目的地再打开。Docker 将应用及其依赖打包成标准容器,实现"Build Once,Run Anywhere"。
5、Docker 的特性
| 特性 | 集装箱 | Docker |
|---|---|---|
| 打包对象 | 几乎任何货物 | 任何软件及其依赖 |
| 硬件依赖 | 标准形状和接口 | 无需修改即可运行在多种平台 |
| 隔离性 | 集装箱可重叠运输 | 资源、网络、库隔离 |
| 自动化 | 标准接口便于装卸 | run、start、stop 等标准化操作 |
| 高效性 | 无需开箱,快速搬运 | 轻量级,快速启动和迁移 |
| 职责分工 | 货主关心货物,承运方关心运输 | 开发关心代码,运维关心基础环境 |
二、容器生态系统
容器生态系统包含三个层次:
- 容器核心技术
- 容器平台技术
- 容器支持技术
1、容器核心技术
容器核心技术是指能够让 container 在 host OS 上运行起来的技术,包括:
- 容器规范
- 容器 runtime
- 容器管理工具
- 容器定义工具
- Registries
- 容器 OS
(1)容器规范
OCI(Open Container Initiative)由 Docker、CoreOS、Google 等公司共同成立,目的是制定开放的容器规范。
目前 OCI 发布了两个规范:
- runtime spec
- image format spec
有了这两个规范,不同组织和厂商开发的容器能够在不同的 runtime 上运行,保证了容器的可移植性和互操作性。
(2)容器 runtime
runtime 是容器真正运行的地方,需要跟操作系统 kernel 紧密协作。
主流容器 runtime:
- lxc:Linux 上老牌的容器 runtime,Docker 最初使用 lxc。
- runc:Docker 自己开发的容器 runtime,符合 OCI 规范,是 Docker 的默认 runtime。
- rkt:CoreOS 开发的容器 runtime,符合 OCI 规范。
(3)容器管理工具
- lxd:lxc 对应的管理工具。
- docker engine:runc 的管理工具,包含后台 daemon 和 cli。
- rkt cli:rkt 的管理工具。
(4)容器定义工具
- docker image:Docker 容器的模板,runtime 依据 docker image 创建容器。
- dockerfile:包含若干命令的文本文件,可以通过这些命令创建出 docker image。
- ACI:App Container Image。
(5)Registry
容器通过 image 创建,需要仓库统一存放 image,这个仓库叫做 Registry。
- Docker Registry:企业可构建私有 Registry。
- Docker Hub:Docker 为公众提供的托管 Registry。
- Quay.io:另一个公共托管 Registry。
(6)容器 OS
容器 OS 是专门运行容器的操作系统,通常体积更小、启动更快。
代表:CoreOS、atomic、ubuntu core。
2、容器平台技术
容器平台技术让容器作为集群在分布式环境中运行,包括:
- 容器编排引擎
- 容器管理平台
- 基于容器的 PaaS
(1)容器编排引擎
主流容器编排引擎:
- docker swarm:Docker 开发。
- kubernetes:Google 领导开发,支持 Docker 和 CoreOS 容器。
- mesos + marathon:mesos 是通用集群资源调度平台,与 marathon 一起提供容器编排功能。
(2)容器管理平台
容器管理平台架构在容器编排引擎之上,支持多种编排引擎,提供 application catalog、一键应用部署等功能。
代表:Rancher、ContainerShip。
(3)基于容器的 PaaS
为微服务应用开发人员和公司提供开发、部署和管理应用的平台。
代表:Deis、Flynn、Dokku。
3、容器支持技术
- 容器网络
- 服务发现
- 监控
- 数据管理
- 日志管理
- 安全性
(1)容器网络
- docker network:Docker 原生网络解决方案。
- flannel、weave、calico:第三方开源解决方案。
(2)服务发现
- etcd
- consul
- zookeeper
(3)监控
- docker ps/top/stats
- docker stats API
- sysdig
- cAdvisor/Heapster
- Weave Scope
(4)数据管理
- Flocker
(5)日志管理
- docker logs
- logspout
(6)安全性
- OpenSCAP:能够对容器镜像进行扫描,发现潜在漏洞。
三、安装 Docker
1、环境选择
| 组件 | 选择 |
|---|---|
| 管理工具 | Docker Engine |
| runtime | runc |
| 操作系统 | CentOS Stream 8 |
2、安装操作系统
基于 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
3、卸载旧版本(可选)
bash
[root@docker ~]# yum remove docker-ce
4、安装必要工具
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
[root@localhost ~]# yum makecache
5、安装 Docker CE
bash
[root@docker ~]# yum install -y docker-ce
[root@docker ~]# systemctl enable docker.service --now
6、验证安装
bash
[root@docker ~]# docker --version
Docker version 26.1.3, build b72abbb
[root@docker ~]# systemctl status docker
7、配置镜像加速器
阿里云镜像加速器
bash
[root@docker ~]# sudo mkdir -p /etc/docker
[root@docker ~]# sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://spcqvmfn.mirror.aliyuncs.com"]
}
EOF
[root@docker ~]# sudo systemctl daemon-reload
[root@docker ~]# sudo systemctl restart docker
检查:
bash
[root@docker ~]# docker info
华为云镜像加速器
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
四、运行第一个容器
1、运行 hello-world
bash
[root@docker ~]# docker run hello-world
过程说明:
- 从本地查找 hello-world 镜像,没找到;
- 从 Docker Hub 下载 hello-world 镜像;
- 启动 hello-world 容器。
清空实验环境:
bash
[root@docker ~]# docker rm -f $(docker ps -aq)
[root@docker ~]# docker rmi -f hello-world
2、运行 httpd 容器
bash
[root@docker ~]# docker run -d -p 80:80 httpd
过程说明:
- 从 Docker Hub 下载 httpd 镜像;
- 启动 httpd 容器,并将容器 80 端口映射到 host 80 端口。
浏览器访问 http://[your host os IP],可以看到 Apache 默认页面。
五、Docker C/S 分离部署
1、环境规划
| 主机名 | IP | 作用 |
|---|---|---|
| docker_server | 192.168.108.30 | Docker 服务端 |
| docker_client | 192.168.108.31 | Docker 客户端 |
2、docker_server 配置
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
安装 Docker:
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
[root@localhost ~]# yum makecache
[root@localhost ~]# yum install -y docker-ce
[root@localhost ~]# systemctl enable docker.service --now
配置镜像加速器:
bash
[root@docker_server ~]# vi /etc/docker/daemon.json
{
"registry-mirrors": [
"https://054b8ac70e8010d90f2ac00ef29e6580.mirror.swr.myhuaweicloud.com"
]
}
[root@docker_server ~]# systemctl restart docker
配置 Docker 服务监听 TCP:
bash
[root@docker_server ~]# vim /usr/lib/systemd/system/docker.service
# 在 ExecStart 参数最后添加 -H tcp://0.0.0.0: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
3、docker_client 配置
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
[root@docker_client ~]# yum makecache
[root@docker_client ~]# yum install -y docker-ce-cli
验证:
bash
[root@docker_client ~]# docker run hello-world
# 报错:Cannot connect to the Docker daemon...
[root@docker_client ~]# docker -H 192.168.108.30 run hello-world
[root@docker_client ~]# docker -H 192.168.108.30 images
说明:client 只做管理,image 和 container 存储在 server 端。
六、容器架构详解
1、容器发展史
- 1979:Unix V7 引入 Chroot Jail。
- 1982:Chroot 加入 BSD。
- 2000:FreeBSD Jail。
- 2001:Linux VServer。
- 2004:Solaris Containers。
- 2006:Google 推出 Process Containers,后命名为 cgroups。
- 2008:LXC。
- 2013:Docker 第一个版本发布。
- 2014:Google 推出 LMCTFY;CoreOS 发布 rkt。
2、Docker 架构
Docker 采用 Client/Server 架构,主要组件:
- Docker 客户端(Client)
- Docker 服务器(Docker daemon)
- Docker 镜像(Image)
- Registry
- Docker 容器(Container)
Docker 内部实现:
- 用户使用 Docker Client 与 Docker Daemon 建立通信。
- Docker Daemon 提供 Docker Server 功能,接受请求。
- Docker Engine 执行内部工作,每项工作以 job 形式存在。
- 需要容器镜像时,从 Docker Registry 下载,通过 Graph driver 存储。
- 需要网络环境时,通过 Network driver 创建配置。
- 需要限制资源或执行用户指令时,通过 Exec driver 完成。
- Libcontainer 独立容器管理包,Network driver 和 Exec driver 通过它操作容器。
3、Docker 组件协作
以 docker run -d -p 80:80 httpd 为例:
- Docker 客户端执行
docker run。 - Docker daemon 发现本地没有 httpd 镜像。
- daemon 从 Docker Hub 下载镜像。
- 下载完成,镜像 httpd 保存到本地。
- Docker daemon 启动容器。
bash
[root@docker ~]# docker images
[root@docker ~]# docker ps
七、Docker 镜像
1、最小镜像 hello-world
bash
[root@docker ~]# docker pull hello-world
[root@docker ~]# docker images
[root@docker ~]# docker run hello-world
hello-world 的 Dockerfile:
dockerfile
FROM scratch
COPY hello /
CMD ["/hello"]
2、base 镜像
base 镜像含义:
- 不依赖其他镜像,从 scratch 构建;
- 其他镜像可以以它为基础进行扩展。
常见 base 镜像:Ubuntu、Debian、CentOS、Alpine。
bash
[root@docker ~]# docker pull centos:7
Linux 操作系统由内核空间和用户空间组成,base 镜像只提供 rootfs,底层共用 Host kernel。
3、镜像分层结构
Docker 镜像采用分层结构,每安装一个软件,就在现有镜像基础上增加一层。
可写的容器层:
- 容器启动时,一个新的可写层加载到镜像顶部;
- 所有对容器的改动只发生在容器层;
- 容器层下面的所有镜像层都是只读的。
对容器增删改查:
| 操作 | 具体执行 |
|---|---|
| 创建文件 | 新文件只能被添加在容器层中 |
| 删除文件 | 在容器层记录删除操作,UnionFS 创建 whiteout 文件遮挡 |
| 修改文件 | 将镜像层数据复制到容器层修改,Copy-on-Write |
| 读取文件 | 由上往下依次查找 |
4、构建镜像
Docker 提供两种构建镜像的方法:
docker commitDockerfile
(1)docker commit
bash
[root@docker ~]# docker run -it ubuntu
root@8dbdf6d3d88:/# apt-get update
root@8dbdf6d3d88:/# apt-get install -y vim
# 新窗口查看容器
[root@docker ~]# docker ps
[root@docker ~]# docker commit 8dbdf6d3d88 ubuntu-with-vim
[root@docker ~]# docker images
[root@docker ~]# docker run -it ubuntu-with-vim
root@4d071cf3014f:/# which vim
不推荐使用 docker commit,因为容易出错、效率低、无法审计。
(2)Dockerfile 构建镜像
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 .
查看镜像分层:
bash
[root@docker ~]# docker history ubuntu-with-vim-dockerfile
缓存特性:如果某镜像层已经存在,直接使用缓存。使用 --no-cache 可禁用缓存。
(3)调试 Dockerfile
bash
[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 .
失败后可用 docker run -it busybox 进入调试。
5、Dockerfile 常用指令
| 指令 | 作用 |
|---|---|
| FROM | 指定 base 镜像,第一条必须是 FROM |
| MAINTAINER | 设置镜像作者 |
| COPY | 将文件从 build context 复制到镜像 |
| ADD | 类似 COPY,归档文件会自动解压 |
| ENV | 设置环境变量 |
| EXPOSE | 指定容器监听端口 |
| VOLUME | 声明 volume |
| WORKDIR | 设置当前工作目录 |
| RUN | 在容器中运行指定命令 |
| CMD | 容器启动时运行指定命令,可被 docker run 参数替换 |
| ENTRYPOINT | 设置容器启动时运行的命令 |
6、RUN vs CMD vs ENTRYPOINT
- RUN:执行命令并创建新的镜像层,常用于安装软件包。
- CMD :设置容器启动后默认执行的命令及其参数,但能被
docker run后面跟的命令行参数替换。 - ENTRYPOINT:配置容器启动时运行的命令。
Shell 格式与 Exec 格式:
dockerfile
# Shell 格式
RUN apt-get install python3
CMD echo "Hello world"
ENTRYPOINT echo "Hello world"
# Exec 格式
RUN ["apt-get", "install", "python3"]
CMD ["/bin/echo", "Hello world"]
ENTRYPOINT ["/bin/echo", "Hello world"]
最佳实践:
- 使用 RUN 指令安装应用和软件包,构建镜像。
- 如果 Docker 镜像的用途是运行应用程序或服务,优先使用 Exec 格式的 ENTRYPOINT。
- 如果想为容器设置默认启动命令,可使用 CMD。
7、Dockerfile 案例
(1)配置 SSH 镜像
bash
[root@docker ~]# vim centos.ssh.dockerfile
FROM centos:8.4.2105
MAINTAINER gaoqiaodong
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"]
[root@docker ~]# docker build -t centos:ssh -f centos.ssh.dockerfile .
[root@docker ~]# docker run -d -p 2022:22 --name sshtest centos:ssh
[root@docker ~]# ssh root@localhost -p 2022
(2)httpd 镜像
bash
[root@docker ~]# vim httpd.dockerfile
FROM centos:8.4.2105
MAINTAINER gaoqiaodong
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
[root@docker ~]# docker build -t httpd:centos -f httpd.dockerfile .
[root@docker ~]# docker run -d -p 80:80 --name myweb httpd:centos
[root@docker ~]# curl localhost
(3)自定义 mycentosjava8
bash
[root@docker ~]# mkdir ProjectJava ; cd ProjectJava
[root@docker ProjectJava]# vim Dockerfile
FROM centos:8.4.2105
MAINTAINER gaoqiaodong<6946630@qq.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
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 -y install vim
RUN yum -y install net-tools
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
ADD jdk-8u461-linux-x64.tar.gz /usr/local/java/
ENV JAVA_HOME /usr/local/java/jdk1.8.0_461
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH
EXPOSE 80
CMD echo $MYPATH
CMD echo "success--------ok"
CMD /bin/bash
[root@docker ProjectJava]# docker build -t centosjava8:461 .
[root@docker ProjectJava]# docker run -it centosjava8:461 /bin/bash
8、镜像命名与分发
镜像名称格式:
[image name] = [repository]:[tag]
完整格式:registry-host:port/username/xxx:tag
打 tag:
bash
[root@docker ~]# docker tag myimage-v1.9.1 myimage:1
[root@docker ~]# docker tag myimage-v1.9.1 myimage:1.9
[root@docker ~]# docker tag myimage-v1.9.1 myimage:1.9.1
[root@docker ~]# docker tag myimage-v1.9.1 myimage:latest
9、使用公共 Registry
Docker Hub
bash
[root@docker ~]# docker login -u ga0qd
[root@docker ~]# docker tag httpd ga0qd/httpd:v1
[root@docker ~]# docker push ga0qd/httpd:v1
[root@docker ~]# docker pull ga0qd/httpd:v1
华为云 SWR
bash
[root@docker ~]# docker login -u cn-east-3@HST3WGZY13FUTQ9ZC32 -p b8e7d74da04a90cb0b1ac08ff894cebe6a8fc039f494ded08cbc64095761aab swr.cn-east-3.myhuaweicloud.com
[root@docker ~]# docker tag httpd:centos swr.cn-east-3.myhuaweicloud.com/gaoqiaodong/centos_httpd:v1
[root@docker ~]# docker push swr.cn-east-3.myhuaweicloud.com/gaoqiaodong/centos_httpd:v1
[root@docker ~]# docker pull swr.cn-east-3.myhuaweicloud.com/gaoqiaodong/centos_httpd:v1
10、搭建本地 Registry
bash
[root@docker ~]# docker run -d -p 5000:5000 -v /myregistry:/var/lib/registry registry:2
[root@docker ~]# docker tag httpd:latest localhost:5000/httpd:v1
[root@docker ~]# docker push localhost:5000/httpd:v1
[root@docker ~]# docker pull localhost:5000/httpd:v1
11、企业级私有仓库 Harbor
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
[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
[root@docker harbor]# cp -ar harbor.yml.tmpl harbor.yml
[root@docker harbor]# vim harbor.yml
# 修改 hostname、harbor_admin_password
[root@docker harbor]# ./prepare
[root@docker harbor]# ./install.sh
登录 Web:http://192.168.108.30
推送镜像:
bash
[root@docker ~]# docker login 192.168.108.30
[root@docker ~]# docker tag nginx:latest 192.168.108.30/cloud/nginx:latest
[root@docker ~]# docker push 192.168.108.30/cloud/nginx:latest
[root@docker ~]# docker pull 192.168.108.30/cloud/nginx
卸载 Harbor:
bash
[root@docker harbor]# docker compose down
[root@docker harbor]# docker images | grep harbor | awk '{print $1":"$2}' | xargs docker rmi
[root@docker harbor]# rm -rf /data
[root@docker ~]# rm -rf /opt/harbor/
12、镜像常用操作小结
| 命令 | 作用 |
|---|---|
| images | 显示镜像列表 |
| history | 显示镜像构建历史 |
| commit | 从容器创建新镜像 |
| build | 从 Dockerfile 构建镜像 |
| tag | 给镜像打 tag |
| pull | 从 registry 下载镜像 |
| push | 将镜像上传到 registry |
| rmi | 删除 Docker host 中的镜像 |
| search | 搜索 Docker Hub 中的镜像 |
| save | 将本地镜像保存为文件 |
| load | 导入本地镜像文件 |
bash
[root@docker ~]# docker save httpd -o httpd.tar
[root@docker ~]# docker load -i images.tar
八、Docker 容器
1、如何运行容器?
docker run = docker create + docker start
bash
[root@docker ~]# docker create ubuntu
[root@docker ~]# docker ps -a
[root@docker ~]# docker start ebla0ca86b2
[root@docker ~]# docker run ubuntu pwd
让容器长期运行:
bash
[root@docker ~]# docker run ubuntu /bin/bash -c "while true ; do sleep 1 ; echo hahaha; done"
[root@docker ~]# docker run -d ubuntu /bin/bash -c "while true ; do sleep 1 ; echo hahaha; done"
运行 httpd:
bash
[root@docker ~]# docker run --name "my_http_server" -d httpd
2、两种进入容器的方法
docker attach
bash
[root@docker ~]# docker run -d ubuntu /bin/bash -c "while true ; do sleep 1 ; echo I_am_in_container ; done"
[root@docker ~]# docker attach dc508b94447f
退出:Ctrl+p 然后 Ctrl+q。
docker exec
bash
[root@docker ~]# docker exec -it <container> bash
区别:
- attach 直接进入容器启动命令的终端,不会启动新进程;
- exec 在容器中打开新的终端,可以启动新进程。
查看日志:
bash
[root@docker ~]# docker logs -f dc508b94447f
3、容器常用操作
bash
docker stop <container>
docker start <container>
docker restart <container>
docker pause <container>
docker unpause <container>
docker rm <container>
docker rm -f $(docker ps -aq)
docker rm -v $(docker ps -aq -f status=exited)
--restart=always:
bash
[root@docker ~]# docker run -d --restart=always httpd
4、容器状态机
容器状态转换:
- created
- running
- stopped
- paused
- deleted
docker create 创建容器处于 Created 状态;docker start 启动;docker run 是 docker create 和 docker start 的组合。
5、限制容器资源
内存限额
bash
[root@docker ~]# docker run -it -m 200M --memory-swap=300M ubuntu-with-stress --vm 1 --vm-bytes 280M -v
参数:
-m或--memory:内存使用限额;--memory-swap:内存 + swap 使用限额。
CPU 限额
bash
[root@docker ~]# docker run --name "container_A" -it -c 1024 ubuntu-with-stress --cpu 4 -v
[root@docker ~]# docker run --name "container_B" -it -c 512 ubuntu-with-stress --cpu 4 -v
-c 或 --cpu-shares 设置容器使用 CPU 的权重,默认 1024。
6、export 和 import 容器
bash
[root@docker ~]# docker export httpd1 -o myhttpd.tar
[root@docker ~]# docker import myhttpd.tar myweb:v1
对比:
docker save:保存镜像所有元数据和历史记录;docker export:导出容器文件系统,丢失元数据和历史记录。
7、底层技术:cgroup 和 namespace
- cgroup:实现资源限额;
- namespace:实现资源隔离。
namespace 类型:
- UTS:hostname
- IPC:共享内存和信号量
- PID:进程隔离
- Network:网卡、IP、路由
- User:用户隔离
bash
[root@docker ~]# docker run -h myhost -it ubuntu
root@myhost:/# hostname
myhost
九、Docker 网络
1、none 和 host 网络
bash
[root@docker ~]# docker network ls
none 网络
bash
[root@docker ~]# docker run -it --network=none busybox
/ # ifconfig
只有 lo,无法与外界通信。
host 网络
bash
[root@docker ~]# docker run -it --network=host busybox
/ # ip a
容器共享宿主机的 network namespace。
2、bridge 网络
Docker 安装时会创建 docker0 网桥。容器默认挂到 docker0。
bash
[root@docker ~]# yum install -y bridge-utils
[root@docker ~]# brctl show
[root@docker ~]# docker run -itd --name busybox1 busybox
[root@docker ~]# brctl show
[root@docker ~]# docker exec -it busybox1 sh
/ # ip a
查看 bridge 网络配置:
bash
[root@docker ~]# docker network inspect bridge
3、自定义网络
bash
[root@docker ~]# docker network create --driver bridge my_net
[root@docker ~]# docker network create --driver bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my_net2
[root@docker ~]# docker run -it --network=my_net2 --name busybox2 busybox
[root@docker ~]# docker run -it --network=my_net2 --ip 172.22.16.8 --name busybox3 busybox
注意:只有使用 --subnet 创建的网络才能指定静态 IP。
4、容器之间连通性
同一网络中的容器、网关可以通信:
bash
/ # ping -c 3 172.22.16.8
/ # ping -c 3 172.22.16.1
不同网络默认不能通信,可通过 docker network connect 将容器加入指定网络:
bash
[root@docker ~]# docker network connect my_net2 busybox1
5、容器间通信方式
- IP 通信;
- Docker DNS Server:
--name容器名通信; - joined 容器:
--network=container:web1。
bash
[root@docker ~]# docker run -it --network my_net2 --name bbox1 busybox
[root@docker ~]# docker run -it --network my_net2 --name bbox2 busybox
[root@docker ~]# docker exec -it bbox2 ping -c 3 bbox1
6、容器访问外部世界
查看 NAT 规则:
bash
[root@docker ~]# iptables -t nat -S
容器默认可以访问外网,关键就是 NAT。
7、外部世界访问容器
端口映射:
bash
[root@docker ~]# docker run -d -p 80 httpd
[root@docker ~]# docker port 93e6a0ad79c2
[root@docker ~]# docker run -d -p 8080:80 httpd
[root@docker ~]# curl 192.168.108.30:8080
8、实战:安装 tomcat
bash
[root@docker ~]# docker search tomcat
[root@docker ~]# docker pull tomcat
[root@docker ~]# docker run -itd -p 8080:8080 tomcat
[root@docker ~]# docker exec -it 92d bash
root@92d78922526b:/usr/local/tomcat# mv webapps.dist/* webapps
再次访问 http://192.168.108.30:8080。
十、Docker 存储
1、两类存储资源
- 由 storage driver 管理的镜像层和容器层;
- Data Volume。
查看 storage driver:
bash
[root@docker ~]# docker info | grep "Storage Driver"
Storage Driver: overlay2
2、Data Volume 之 bind mount
bash
[root@docker ~]# mkdir htdocs
[root@docker ~]# vim htdocs/index.html
<html><body><h1>This is a file in host file system !</h1></body></html>
[root@docker ~]# docker run -d -p 80:80 -v ~/htdocs:/usr/local/apache2/htdocs httpd
[root@docker ~]# curl 127.0.0.1:80
只读权限:
bash
[root@docker ~]# docker run -d -p 80:80 -v ~/htdocs:/usr/local/apache2/htdocs:ro httpd
单文件挂载:
bash
[root@docker ~]# docker run -d -p 80:80 -v ~/htdocs/index.html:/usr/local/apache2/htdocs/new_index.html httpd
3、Data Volume 之 docker managed volume
bash
[root@docker ~]# docker run -d -p 80:80 -v /usr/local/apache2/htdocs httpd
[root@docker ~]# docker inspect c75f36c4bf32
Source 为 /var/lib/docker/volumes/.../_data。
4、volume container
bash
[root@docker ~]# docker create --name vc_data \
-v ~/htdocs:/usr/local/apache2/htdocs \
-v /other/useful/tools \
busybox
[root@docker ~]# docker run --name web1 -d -p 80 --volumes-from vc_data httpd
[root@docker ~]# docker run --name web2 -d -p 80 --volumes-from vc_data httpd
[root@docker ~]# docker run --name web3 -d -p 80 --volumes-from vc_data httpd
5、data-packed volume container
bash
[root@docker ~]# vim Dockerfile
FROM busybox:latest
ADD htdocs /usr/local/apache2/htdocs
VOLUME /usr/local/apache2/htdocs
[root@docker ~]# docker build -t datapacked .
[root@docker ~]# docker create --name vc_data datapacked
[root@docker ~]# docker run -d -p 80:80 --volumes-from vc_data httpd
6、volume 生命周期管理
备份、恢复、迁移、销毁:
bash
[root@docker ~]# docker run --name bbox -v /test/data busybox
[root@docker ~]# docker volume ls
[root@docker ~]# docker rm bbox
[root@docker ~]# docker volume rm <volume_name>
[root@docker ~]# docker volume prune
7、实战:安装 MySQL
bash
[root@docker ~]# docker pull mysql:5.7
[root@docker ~]# docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7
[root@docker ~]# docker exec -it cf4065b04c9d bash
bash-4.2# mysql -uroot -p123456
mysql> CREATE DATABASE db01;
mysql> USE db01;
mysql> CREATE TABLE tablea(id int,name varchar(20));
中文乱码解决:
bash
[root@docker ~]# mkdir -p /gqd/mysql/conf
[root@docker ~]# vim /gqd/mysql/conf/my.cnf
[mysqld]
character_set_server=utf8
collation_server=utf8_general_ci
[mysql]
default_character_set=utf8
[root@docker ~]# docker run -d -p 3306:3306 --privileged=true \
-v /gqd/mysql/log:/var/log/mysql \
-v /gqd/mysql/data:/var/lib/mysql \
-v /gqd/mysql/conf:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7
十一、容器监控
1、docker ps
bash
[root@docker ~]# docker ps
2、docker top
bash
[root@docker ~]# docker top sshtest
[root@docker ~]# docker top sshtest -au
3、docker stats
bash
[root@docker ~]# docker stats
4、cAdvisor
bash
[root@docker ~]# docker run \
--volume=/var/run:/var/run:rw \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker:/var/lib/docker:ro \
--publish=8080:8080 \
--detach=true \
--name=cadvisor \
google/cadvisor:latest
访问 http://[Host_IP]:8080。
十二、容器日志
bash
[root@docker ~]# docker run -d -p 80:80 httpd
[root@docker ~]# docker logs a8286845e6f8
[root@docker ~]# docker logs -f a8286845e6f8
docker logs 能打印自容器启动以来的完整日志,-f 持续打印新日志。
十三、Docker Compose
1、概念
- 服务(service):一个应用的容器;
- 项目(project):由一组关联的应用容器组成的完整业务单元,在
docker-compose.yml中定义。
2、命令说明
bash
[root@docker ~]# docker compose version
Docker Compose version v2.27.0
常用命令:
bash
docker compose up -d
docker compose down
docker compose ps
docker compose logs
docker compose restart
3、Compose 模板
yaml
version: "2"
services:
webapp:
image: httpd
4、实战:WordPress
bash
[root@docker ~]# mkdir wordpress
[root@docker ~]# cd wordpress/
[root@docker wordpress]# vim docker-compose.yml
services:
blog:
image: wordpress:latest
restart: always
links:
- db
ports:
- "80:80"
environment:
- WORDPRESS_DB_HOST=db
- WORDPRESS_DB_USER=root
- WORDPRESS_DB_PASSWORD=huawei
- WORDPRESS_DB_NAME=wordpress
db:
image: mysql:latest
restart: always
environment:
- MYSQL_ROOT_PASSWORD=huawei
- MYSQL_DATABASE=wordpress
[root@docker wordpress]# docker compose config -q
[root@docker wordpress]# docker compose up -d
[root@docker wordpress]# docker ps
浏览器访问 http://192.168.108.30/wp-admin/install.php。
十四、Docker 图形界面管理
1、DockerUI
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
访问 http://192.168.108.30:8999,默认用户名密码:ginghan/123456。
2、Portainer
bash
[root@docker ~]# docker volume create portainer_data
[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
访问 https://ip:9443,首次访问需要创建管理员账号。
查看 setup token:
bash
[root@docker ~]# docker logs portainer
十五、综合实验
1、构建 WordPress
bash
[root@docker ~]# docker pull mysql
[root@docker ~]# docker pull wordpress
[root@docker ~]# docker run -d -p 3306:3306 \
-v /mysql:/var/lib/mysql:z \
--name mysql \
-e MYSQL_ROOT_PASSWORD=huawei \
-e MYSQL_DATABASE=wordpress \
mysql
[root@docker ~]# docker run -d -p 80:80 \
--name wordpress \
--link mysql:mysql \
-e WORDPRESS_DB_HOST=mysql \
-e WORDPRESS_DB_USER=root \
-e WORDPRESS_DB_PASSWORD=huawei \
-e WORDPRESS_DB_NAME=wordpress \
wordpress
浏览器访问 http://192.168.108.30/wp-admin/install.php。
2、部署 Ghost 开源内容管理系统
bash
[root@docker ~]# docker pull ghost
[root@docker ~]# mkdir -p /data/ghost
[root@docker ~]# docker run -d \
--restart always \
--name ghost \
-p 2368:2368 \
-v /data/ghost:/var/lib/ghost/content \
-e NODE_ENV=development \
-e url=http://localhost:2368 \
ghost
[root@docker ~]# chmod -R 777 /data/ghost/
[root@docker ~]# docker restart ghost
[root@docker ~]# docker ps
[root@docker ~]# docker logs ghost
访问 http://192.168.108.30:2368,进入注册页面:
http://192.168.108.30:2368/ghost
十六、总结
本文系统整理了 Docker 容器技术的核心知识,包括:
- 容器生态系统的核心技术、平台技术和支持技术;
- Docker 安装、镜像加速器、C/S 分离部署;
- Docker 架构、镜像分层、Dockerfile 构建;
- 容器运行、进入、状态管理、资源限制;
- Docker 网络:none、host、bridge、自定义网络、容器通信;
- Docker 存储:bind mount、docker managed volume、volume container、data-packed volume container;
- 容器监控、日志、Compose、图形化管理;
- WordPress、Ghost 等综合实验。
掌握这些内容后,可以比较熟练地使用 Docker 部署和管理容器化应用,并理解容器背后的核心原理。后续可以继续学习 Kubernetes、Harbor、CI/CD、服务网格等进阶技术。