更多技术资料关注乐维社区https://forum.lwops.cn/

前言

2010年,几个搞IT的年轻人,在美国旧金山成立了一家名叫“dotCloud”的公司。

这家公司主要提供基于PaaS的云计算技术服务。具体来说,是和LXC有关的容器技术。

后来, dotCloud公司将自己的容器技术进行了简化和标准化,并命名为——Docker。

Docker技术诞生之后,并没有引起行业的关注。而dotCloud公司,作为一家小型创业企业,在激烈的竞争之下,也步履维艰。

正当他们快要坚持不下去的时候,脑子里蹦出了“开源”的想法。

2013年3月, dotCloud公司的创始人之一 , Docker之父, 28岁的Solomon Hykes正式决定,将Docker项目开源。

不开则已, 一开惊人。

越来越多的IT工程师发现了Docker的优点,然后蜂拥而至,加入Docker开源社区。

Docker的人气迅速攀升,速度之快,令人瞠目结舌。

开源当月, Docker 0.1 版本发布。此后的每一个月, Docker都会发布一个版本。到2014年6月9日, Docker 1.0 版本正式发布。

此时的Docker,已经成为行业里人气最火爆的开源技术,没有之一。甚至像Google、微软、 Amazon、 VMware这样的巨头,都对它青睐有加,表示将全力支持。

Docker火了之后, dotCloud公司干脆把公司名字也改成了Docker Inc. 。

Docker和容器技术为什么会这么火爆?说白了,就是因为它“轻”。

在容器技术之前,业界的网红是虚拟机。虚拟机技术的代表,是VMWare和OpenStack。

相信很多人都用过虚拟机。虚拟机,就是在你的操作系统里面,装一个软件,然后通过这个软件,再模拟一台甚至多台“子电脑” 出来。

在“子电脑”里,你可以和正常电脑一样运行程序,例如开QQ。如果你愿意,你可以变出好几个“子电脑”,里面都开QQ。“子电脑”和“子电脑”之间,是相互隔离的,互不影响。

虚拟机属于虚拟化技术。而Docker这样的容器技术,也是虚拟化技术,属于轻量级的虚拟化。

虚拟机虽然可以隔离出很多“子电脑”,但占用空间更大,启动更慢,虚拟机软件可能还要花钱(例如VMWare)。

而容器技术恰好没有这些缺点。它不需要虚拟出整个操作系统,只需要虚拟一个小规模的环境(类似“沙箱”)。

它启动时间很快,几秒钟就能完成。而且,它对资源的利用率很高(一台主机可以同时运行几千个Docker容器)。此外,它占的空间很小,虚拟机一般要几GB到几十GB的空间,而容器只需要MB级甚至KB级。

特性 虚拟机 容器
隔离级别 操作系统级 进程级
隔离策略 Hypervisor CGroups
系统资源 5~15% 0~5%
特性 虚拟机 容器
启动时间 分钟级 秒级
镜像存储 GB-TB KB-MB
集群规模 上百 上万
高可用策略 备份、容灾、迁移 弹性、负载、动态

正因为如此,容器技术受到了热烈的欢迎和追捧,发展迅速。

大家需要注意, Docker本身并不是容器,它是创建容器的工具,是应用容器引擎。

想要搞懂Docker,其实看它的两句口号就行。

第一句,是“Build, Ship and Run”。也就是, “搭建、发送、运行”,三板斧。

举个例子:

我来到一片空地,想建个房子,于是我搬石头、砍木头、画图纸, 一顿操作,终于把这个房子盖好了。

结果,我住了一段时间,想搬到另一片空地去。这时候,按以往的办法,我只能再次搬石头、砍木头、画图纸、盖房子。

但是,跑来一个老巫婆,教会我一种魔法。

这种魔法,可以把我盖好的房子复制一份,做成“镜像” ,放在我的背包里。

等我到了另一片空地,就用这个“镜像” ,复制一套房子,拎包入住。

所以, Docker的第二句口号就是: “Build once , Run anywhere(搭建一次,到处能用) ”。

Docker技术的三大核心概念,分别是: 镜像(Image)容器(Container)仓库(Repository)

刚才例子里面,那个放在包里的“镜像” ,就是Docker镜像。而我的背包,就是Docker仓库。我在空地上,用魔法造好的房子,就是一个Docker容器。

说白了,这个Docker镜像,是一个特殊的文件系统。它除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(例如环境变量)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

也就是说,每次变出房子,房子是一样的,但生活用品之类的,都是不管的。谁住谁负责添置。

每一个镜像可以变出一种房子。那么,我可以有多个镜像呀!

也就是说,我盖了一个欧式别墅,生成了镜像。另一个哥们可能盖了一个中国四合院,也生成了镜像。还有哥们,盖了一个非洲茅草屋,也生成了镜像。

这么一来,我们可以交换镜像,你用我的,我用你的

于是乎,就变成了一个大的公共仓库。

负责对Docker镜像进行管理的,是Docker Registry服务(类似仓库管理员)。

不是任何人建的任何镜像都是合法的。万一有人盖了一个有问题的房子呢?

所以, Docker Registry服务对镜像的管理是非常严格的。

最常使用的Registry公开服务,是官方的Docker Hub,这也是默认的 Registry,并拥有大量的高质量的官方镜像。

1、什么是容器

1.1 什么是容器

容器就是在隔离的环境运行的一个进程,如果进程停止,容器就会退出。隔离的环境拥有自己的系统文件, ip地址,主机名等kvm虚拟机, linux,系统文件。

百度百科解释(引用于百度百科图片):
容器(器皿)
编辑
讨论
日本词条由"科普中国"科学百科词条编写与应用工作项目审核。
容器是指用以容纳物料并以壳体为主的基本装置。常用作储存设备或其他化工设备的外壳。主要由壳体、封头、接管、法兰和支座组成。对容器的基本要求是:满足工艺需要;保证操作安全,包括具有足够的强度、刚度以及密封性;耐腐蚀,具有一定的使用寿命;便于制造、安装、维修和使用;成本低,材料节省,尤其要节约不锈钢和有色金属等贵重材料。容器在化工生产中应用广泛,按压力分有真空、常压、外压的压力容器,压力容器又可分低压、中压、高压及超高压容器;按温度分有常温、低温及高温容器;按筒体结构分有单层容器和多层容器;按工艺用途分有储存、分离、反应及换热容器;按厚度分有薄壁和厚壁容器。

定义2
中文名
能将其他控件放置在其上面的控件
外文名
container:vessel
定义1
用途
包装或装载物品的贮存器

容器是一种基础工具;泛指可以容纳其他物品的工具。可以部分或者完全封闭,被用于容纳、存储、运输物品;物体可以被放置在容器中,容器可以保护内容物。人类使用容器的历史,至少有数十万乃至百万年。例如:瓶、罐、箱、篮、桶、杯。

1.2 主机虚拟化与容器的区别

LXC,(linuxcontainer)将原来需要手工编码实现的容器技术,进行了封装。实现了,更加方便、快速的容器创建及管理的技术。通过固有“模板” ,安装并启动容器。将远程的程序包下载到本地,安装并创建好我们需要的容器。确实, LXC已经很大程度上降低了容器管理的难度,但是依然使用一些弊端。有些时候可能需要自定制模板,以及使用LXC中自带的模板,以及大规模创建及复制依然比较麻烦。所以,很难大规模的应用。所以,出现了Docker技术。 Docker是在LXC基础上,使用GoLang二次开发的封装版。

容器相当于你运行了一个接近于裸机的虚拟机。这项技术始于2008年, LXC的大部分功能来自于Solaris容器(又叫做Solaries Zones)以及之前的FreeBSD jails技术。 LXC并不是创建一个成熟的虚拟机,而是创建了一个拥有自己进程和网络空间的虚拟环境,使用命名空间来强制进程隔离并利用内核的控制组(cgroups)功能,该功能可以限制,计算和隔离一个或多个进程的CPU,内存,磁盘I / O和网络使用情况。 您可以将这种用户空间框架想像成是 chroot 的高级形式。

chroot 是一个改变当前运行进程以及其子进程的根目录的操作。 一个运行在这种环境的程序无法访问根目录外的文件和命令。

注意: LXC使用命名空间来强制进程隔离,同时利用内核的控制组来计算以及限制一个或多个进程的CPU,内存,磁盘I / O和网络使用。

但容器是将软件应用程序与操作系统分离,为用户提供干净且最小的Linux环境,与此同时在一个或多个隔离的“容器” 中运行其他所有内容。容器的目的是启动一组有限数量的应用程序或服务(通常称为微服务),并使它们在独立的沙盒环境中运行。

2、docker容器的安装

2.1 安装前准备

centos7.8 2台
主机名: docker01
IP: 192.168.26.201
主机名: docker02
IP: 192.168.26.202

注:此处关闭了防火墙和selinux,两台机器均可联网,两块网卡,分别对内和对外。

主机名配置、 hosts配置

[root@docker01 ~]# cat /etc/hosts
1 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
2 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
3 192.168.26.201 docker01
4 192.168.26.202 docker02
plaintext

配置yum源:

[root@docker01 ~]# curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
[root@docker01 ~]# wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.ustc.edu.cn/docker-ce/linux/centos/docker-ce.repo
[root@docker01 ~]# sed -i 's#download.docker.com#mirrors.tuna.tsinghua.edu.cn/docker-ce#g' /etc/yum.repos.d/docker-ce.repo

2.2 安装 docker
bash
运行
[root@docker01 ~]# yum install docker-ce -y
[root@docker01 ~]# systemctl start docker
[root@docker01 ~]# systemctl enable docker
[root@docker01 ~]# docker version
Client: Docker Engine - Community
 Version:           20.10.7
 API version:       1.41
 Go version:        go1.13.15
 Git commit:        f0df350
 Built:             Wed Jun  2 11:58:10 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.7
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       b0f5bc3
  Built:            Wed Jun  2 11:56:35 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.4.6
  GitCommit:        d71fcd7d8303cbf684402823e425e9dd2e99285d
 runc:
  Version:          1.0.0-rc95
  GitCommit:        b9ee9c6314599f1b4a7f497e1f1f856fe433d3b7
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

docker 主要组件有:镜像、容器、仓库,网络,存储启动容器必须需要一个镜像,仓库中只存储镜像 容器 --- 镜像 --- 仓库
2.3 配置 docker 加速
bash
运行
[root@docker01 ~]# vim /etc/docker/daemon.json
{
  "registry-mirrors": ["https://registry.docker-cn.com"]
}
[root@docker01 ~]# systemctl restart docker

3、启动第一个容器
docker 的主要目标是 "Build,Ship and Run any App,Angwhere", 构建,运输,处处运行部署服务,环境问题一次构建,处处运行
docker 是一种软件的打包技术。
docker 初次体验:
安装 Nginx 步骤:
官网下载 Nginx 源码包创建 Nginx
用户编译安装./config.... 修改配置文件,启动
bash
运行
[root@docker01 ~]# docker run -d -p 80:80 nginx

run (创建并启动一个容器)
-d 放在后台
-p 端口映射
nginx docker 镜像的名字
bash
运行
[root@docker01 ~]# docker load -i docker_nginx1.21.tar.gz
[root@docker01 ~]# docker run -d -p 80:80 nginx
a212a7fce91e2bd5c5f446e87e4a59b7119907fb169b7b6f6cbf6877a2d9c0ab
[root@docker01 ~]# ps -ef | grep nginx
root      12998  12976  0 15:20 ?        00:00:00 nginx: master process nginx -g daemon off;
101       13052  12998  0 15:20 ?        00:00:00 nginx: worker process
101       13053  12998  0 15:20 ?        00:00:00 nginx: worker process
root      13055  11546  0 15:20 pts/0    00:00:00 grep --color=auto nginx

4、docker 镜像管理
搜索镜像 docker search
选镜像的建议:
1,优先考虑官方
2 ,stars 数量多
官方镜像仓库地址: hub.docker.com
获取镜像 docker pull(push)
镜像加速器:阿里云加速器, daocloud 加速器,中科大加速器, Docker 中国官方镜像加速: https://registry.docker-cn.com
官方 pull docker pull centos:6.8 (没有指定版本,默认会下载最新版)
私有仓库 pull docker pull daocloud.io/huangzhichong/alpine-cn:latest
查看镜像列表 docker images or docker image ls
删除镜像 docker rmi
例子: docker image rm centos:latest
导出镜像 docker save
例子: docker image save centos -o docker-centos7.4.tar.gz
导入镜像 docker load
例子: docker image load -i docker-centos7.4.tar.gz
bash
运行
[root@docker01 ~]# docker pull busybox
[root@docker01 ~]# docker pull busybox:1.29
1.29: Pulling from library/busybox
b4a6e23922dd: Pull complete
Digest: sha256:8ccbac73d19c0dd4d70b4f0c1e12245b5fa3ad24758a11035ee505c629c0796
Status: Downloaded newer image for busybox:1.29 docker.io/library/busybox:1.29
[root@docker01 ~]# docker image save -o docker_busybox1.29.tar.gz busybox:1.29
[root@docker01 ~]# ls
anaconda-ks.cfg  docker_busybox1.29.tar.gz  docker_nginx1.21.tar.gz
[root@docker01 ~]# docker load -i docker_busybox1.29.tar.gz
23bc2b70b201: Loading layer   1.37MB/1.37MB
Loaded image: busybox:1.29
[root@docker01 ~]# docker images
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
nginx        latest    4f380adfc10f  6 days ago       133MB
busybox      latest    69593048aa3a  3 weeks ago      1.24MB
busybox      1.29      758ec7f3a1ee  2 years ago      1.15MB
[root@docker01 ~]# docker load -i docker_alpine.tar.gz
[root@docker01 ~]# docker load -i docker_centos6.9.tar.gz docker_k8s_dns.tar.gz

5、docker 容器管理
bash
运行
docker run -d -p 80:80 nginx:latest

run :创建并运行一个容器
-d :后台运行
-p :端口映射
nginx :镜像名
bash
运行
docker run -it --name centos6 centos:6.9 /bin/bash

-it :交互式终端
--name :指定容器名称
/bin/bash:覆盖容器初始命令
docker run === docker create + docker start
表格
操作	命令
启动容器	docker start 容器名 / ID
停止容器	docker stop 容器名 / ID
强制杀死	docker kill 容器名 / ID
查看运行容器	docker ps
查看所有容器	docker ps -a
最近容器	docker ps -l
只输出 ID	docker ps -q
进入容器
docker exec(推荐,新建终端,退出不停止容器)
bash
运行
docker exec -it 容器ID/名称 /bin/bash

docker attach(共用同一个终端,退出容器会停止;分离快捷键:ctrl+p,ctrl+q)
bash
运行
docker attach 容器ID/名称

nsenter(已弃用,需安装 util-linux)
删除容器
bash
运行
# 批量删除所有容器
docker rm -f `docker ps -a -q`

核心规则
docker 容器内的第一个进程(初始命令)必须一直前台运行,进程退出则容器停止。
实操示例
bash
运行
[root@docker01 ~]# docker run -it --name centos6 centos:6.9 /bin/bash
[root@10f81d643f3f /]# ps -ef
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 07:50 pts/0    00:00:00 /bin/bash
root         14      1  0 07:50 pts/0    00:00:00 ps -ef
[root@10f81d643f3f /]# exit
exit

[root@docker01 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS
PORTS                                NAMES
a212a7fce91e   nginx     "/docker-entrypoint.… "   31 minutes ago   Up 31 minutes   0.0.0.0:80->80/tcp, :::80->80/tcp   gracious_zhukovsky

[root@docker01 ~]# docker ps -a
CONTAINER ID   IMAGE        COMMAND                  CREATED
STATUS                           PORTS                                NAMES
10f81d643f3f   centos:6.9   "/bin/bash"              About a minute ago
Exited (0) About a minute ago                                        centos6
a212a7fce91e   nginx        "/docker-entrypoint.… "   31 minutes ago       Up 31 minutes   0.0.0.0:80->80/tcp, :::80->80/tcp   gracious_zhukovsky

# 启动停止的容器
[root@docker01 ~]# docker start centos6
centos6

[root@docker01 ~]# docker stop 10f81d643f3f
10f81d643f3f

# 删除容器
[root@docker01 ~]# docker rm 10f81d643f3f
10f81d643f3f

# 批量强制删除所有容器
[root@docker01 ~]# docker rm -f `docker ps -a -q`

区分 attach 与 exec
bash
运行
# attach 共用终端
[root@docker01 ~]# docker attach 3ddb8f03e85f

# exec 新建终端(推荐)
[root@docker01 ~]# docker run -it centos:6.9 /bin/bash
[root@docker01 ~]# docker exec -it fc5c09861a54 /bin/bash
[root@fc5c09861a54 /]# ps -ef
UID         PID   PPID  C STIME TTY          TIME CMD
root          1      0  0 07:58 pts/0    00:00:00 /bin/bash
root         14      0  0 07:58 pts/1    00:00:00 /bin/bash
root         28     14  0 07:59 pts/1    00:00:00 ps -ef
# 向原终端输出内容
[root@fc5c09861a54 /]# echo 'hello' > /dev/pts/0

保持容器后台运行方案
容器前台持续阻塞命令示例:tail -f /etc/hosts
bash
运行
# 秒退容器示例(执行完命令直接退出)
[root@docker01 ~]# docker run centos:6.9 echo hello

# 长期存活容器
[root@docker01 ~]# docker run -d -it centos:6.9
91d5a19a1ccf663311d789a97e87a7cc299c107cd58c7c5161c82a99baa71abd
[root@docker01 ~]# docker ps -a -l
CONTAINER ID   IMAGE        COMMAND       CREATED         STATUS PORTS     NAMES
91d5a19a1ccf   centos:6.9   "/bin/bash"   3 seconds ago   Up 3 seconds hopeful_archimedes

Nginx 容器持续运行原理
bash
运行
[root@docker01 ~]# docker run -d nginx:latest
403c2520f4fccefa4db58c9ef0e25aa32eea39e4c7d4b25e7aee23ff3a6ed843
[root@docker01 ~]# docker ps -a -l --no-trunc
CONTAINER ID                                                        IMAGE
COMMAND                                           CREATED          STATUS
PORTS     NAMES
403c2520f4fccefa4db58c9ef0e25aa32eea39e4c7d4b25e7aee23ff3a6ed843
nginx:latest   "/docker-entrypoint.sh nginx -g 'daemon off;'"

关键参数 daemon off; 让 Nginx 以前台进程运行,容器不会退出。
宿主机 Nginx 对比:
bash
运行
[root@nginx ~]# nginx
[root@nginx ~]# ps -ef | grep nginx
root       2901      1  0 16:10 ?        00:00:00 nginx: master process nginx
nginx      2902   2901  0 16:10 ?        00:00:00 nginx: worker process
nginx      2903   2901  0 16:10 ?        00:00:00 nginx: worker process
[root@nginx ~]# nginx -s stop
# 前台启动,不后台守护
[root@nginx ~]# nginx -g 'daemon off;'
# 临时修改运行参数
[root@nginx ~]# nginx -g 'user root;'

6、docker 容器的网络访问(端口映射)
Docker 5 种端口映射方式:
-p hostPort:containerPort 主机所有 IP 映射端口
-p ip:hostPort:containerPort 指定宿主机 IP + 端口映射
-p ip::containerPort 指定 IP,宿主机随机端口
-p hostPort:containerPort/udp UDP 协议端口映射
多端口:-p 80:80 -p 443:443
随机端口映射:docker run -P
底层依靠 iptables NAT 规则实现端口转发。
6.1 -P 随机端口
bash
运行
# 拉取镜像
[root@docker01 ~]# docker pull ghost:alpine
# 随机端口启动
[root@docker01 ~]# docker run -d -P ghost:alpine
c66cfbf6113189cdde45bd1b41bd4f1ab63c6e8890e84eb8012bd47a3315befd
# 查看端口分配
[root@docker01 ~]# docker ps -a -l
CONTAINER ID   IMAGE          COMMAND                  CREATED
STATUS         PORTS                                          NAMES
c66cfbf61131   ghost:alpine   "docker-entrypoint.s… "   4 seconds ago   Up 3 seconds   0.0.0.0:49153->2368/tcp, :::49153->2368/tcp   happy_beaver
# 查看端口监听
[root@docker01 ~]# netstat -ntulp
# 查看iptables转发规则
[root@docker01 ~]# iptables -t nat -L -n

6.2 指定全局端口映射 -p 80:80
bash
运行
[root@docker01 ~]# docker run -d -p 80:80 nginx:latest
525b35bfb37cfe168098860f8ce257ca0f46c3303717f5ae7a655704c028e4c1

多 IP 单端口复用场景
宿主机添加虚拟网卡:
bash
运行
[root@docker01 ~]# ifconfig ens32:1 192.168.222/24 up
# 不同IP绑定80端口
[root@docker01 ~]# docker rm -f `docker ps -a -q`
[root@docker01 ~]# docker run -d -p 192.168.26.201:80:80 nginx:latest
[root@docker01 ~]# docker run -d -p 192.168.26.222:80:2368 ghost:alpine

6.3 指定 IP 随机端口
bash
运行
[root@docker01 ~]# docker run -d -p 192.168.26.201::2368 ghost:alpine
e7e86dcf5c58c95d9b88efc1fdf457dbcdce61e498f23a30f0d20e1d8a9b14e5
[root@docker01 ~]# docker ps -a -l
CONTAINER ID   IMAGE          COMMAND                  CREATED
STATUS         PORTS                             NAMES
e7e86dcf5c58c95d9b88efc1fdf457dbcdce61e498f23a30f0d20e1d8a9b14e5   ghost:alpine   "docker-entrypoint.s… "   5 seconds ago   Up 4 seconds   192.168.201:49153->2368/tcp   relaxed_mclean

7、docker 的数据卷管理
作用:容器数据持久化,容器删除数据不丢失
两种挂载模式:
命名卷:-v 卷名:/容器目录(存储在 docker 默认目录 /var/lib/docker/volumes/)
绑定挂载:-v 宿主机目录:/容器目录(自定义宿主机路径)
配套参数:--volumes-from 复用其他容器数据卷
7.1 小鸟飞飞案例
方式 1:容器内修改,docker cp 上传(不推荐,无持久化)
bash
运行
# 启动nginx
[root@docker01 ~]# docker run -d -p 80:80 nginx:latest
5944383ba681b26bebada5ad8756ddf55d0928983e47205b1564986294f09840
# 进入容器修改首页
[root@docker01 ~]# docker exec -it inspiring_bhabha /bin/bash
root@5944383ba681:/# cd /usr/share/nginx/html/
root@5944383ba681:/usr/share/nginx/html# echo "test" > index.html
root@5944383ba681:/usr/share/nginx/html# exit

# 宿主机上传源码到容器
[root@docker01 opt]# mkdir xiaoniao
# 上传xiaoniaofeifei.zip解压
[root@docker01 opt]# docker cp xiaoniao/ inspiring_bhabha:/usr/share/nginx/html

方式 2:绑定挂载(推荐,宿主机目录直接映射)
bash
运行
# 清空容器,宿主机目录直接挂载网页目录
[root@docker01 opt]# docker rm -f `docker ps -a -q`
[root@docker01 opt]# docker run -d -p 80:80 -v /opt/xiaoniao:/usr/share/nginx/html nginx:latest
8d07900d5add692a2dd5ff413e0c66fbcec22761ad3674a8c363de28f33619a8

方式 3:命名数据卷
bash
运行
# 创建命名卷xiaoniao
[root@docker01 ~]# docker run -d -p 80:80 -v xiaoniao:/usr/share/nginx/html nginx:latest
deb1ad8934422cad3cea168d0a79941e058423e5ec4a8b5ae64d9645e10a6d16
# 查看所有数据卷
[root@docker01 ~]# docker volume ls
# 查看卷真实宿主机路径
[root@docker01 ~]# docker volume inspect xiaoniao
[
  {
    "CreatedAt": "2021-06-29T20:37:15+08:00",
    "Driver": "local",
    "Labels": null,
    "Mountpoint": "/var/lib/docker/volumes/xiaoniao/_data",
    "Name": "xiaoniao",
    "Options": null,
    "Scope": "local"
  }
]
# 直接修改宿主机卷文件,容器同步生效
[root@docker01 ~]# cd /var/lib/docker/volumes/xiaoniao/_data/
[root@docker01 _data]# echo "ssss" > index.html

7.2 练习:Nginx 多站点(80 默认页,81 小鸟飞飞)
方案:挂载配置目录,新增 81 端口站点
bash
运行
# 清理容器
[root@docker01 opt]# docker rm -f `docker ps -a -q`
# 挂载源码目录到容器/opt
[root@docker01 opt]# docker run -d -p 80:80 -p 81:81 -v /opt/xiaoniao:/opt nginx:latest
91a17094ee2fef25fc0405627b22c61919df8df2b1d9a57f64b8634ec5bec457
# 进入容器新增站点配置
[root@docker01 opt]# docker exec -it youthful_carson /bin/bash
root@91a17094ee2f:/etc/nginx/conf.d# echo 'server {
listen 81;
server_name _;
root /opt;
index index.html index.htm;
}' > xiaoniao.conf
root@91a17094ee2f:/etc/nginx/conf.d# exit
# 重载nginx
[root@docker01 opt]# docker restart youthful_carson

8、手动将容器保存为镜像
基础命令
docker commit 容器ID/名称 镜像名:版本
8.1 案例:centos6+httpd+ssh 镜像
启动基础容器,安装服务
bash
运行
[root@docker01 ~]# docker run -it centos:6.9
[root@zz /]# yum install httpd openssh-server -y
# 编写前台启动脚本,保证容器不退出
[root@zz /]# vi /init.sh
#!/bin/bash
/etc/init.d/httpd start
/usr/sbin/sshd -D
[root@zz /]# chmod +x /init.sh

提交生成镜像
bash
运行
docker commit zz centos6-ssh-httpd:v1

测试镜像运行
bash
运行
docker run -d centos6-ssh-httpd:v1 /init.sh

8.2 实战:KodExplorer 可道云镜像制作(Nginx+PHP)
步骤 1:基础环境部署
bash
运行
# 清理旧容器
[root@docker01 ~]# docker rm -f `docker ps -a -q`
# 导入centos7基础镜像
[root@docker01 ~]# docker load -i docker_centos7.tar.gz
# 交互式启动容器
[root@docker01 ~]# docker run -it -p 80:80 centos:7 /bin/bash
# 配置国内yum源
[root@7ca6d8a21482 /]# curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
[root@7ca6d8a21482 /]# curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
# 安装nginx
[root@7ca6d8a21482 /]# yum -y install nginx
# 前台启动测试
[root@7ca6d8a21482 /]# nginx -g 'daemon off;'

步骤 2:部署 PHP 环境
bash
运行
# 进入容器安装php-fpm、扩展
[root@e146e20acc64 /]# yum -y install php-fpm php-gd php-mbstring
# 修改php运行用户为nginx
[root@e146e20acc64 /]# sed -i 's/^user = apache/user = nginx/' /etc/php-fpm.d/www.conf
[root@e146e20acc64 /]# sed -i 's/^group = apache/group = nginx/'
# 重写nginx配置支持php解析
[root@e146e20acc64 /]# grep -Ev '^$|#' /etc/nginx/nginx.conf > /etc/nginx/nginx.conf
[root@e146e20acc64 /]# vi /etc/nginx/nginx.conf
worker_processes  1;
events {
worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   /code;
            index  index.php index.html index.htm;
        }
        location ~ \.php$ {
            root   /code;
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME /code$fastcgi_script_name;
            include  fastcgi_params;
        }
    }
}
# 创建网站目录
[root@e146e20acc64 /]# mkdir /code
# 本地上传kod源码到容器
[root@docker01 ~]# docker cp kodexplorer4.40.zip magical_germain:/code
# 解压授权
[root@e146e20acc64 code]# unzip kodexplorer4.40.zip
[root@e146e20acc64 code]# chmod -R 777 /code/
# 后台启动php-fpm
[root@e146e20acc64 code]# php-fpm -D
# 前台启动nginx
[root@e146e20acc64 code]# nginx -g 'daemon off;'

步骤 3:提交基础 kod 镜像
bash
运行
[root@docker01 ~]# docker commit magical_germain kod:v1
sha256:64bebf19e8894b1e0e922cfaaa5edf80d2094cfeb8d455f81cf68e20ca610e56

步骤 4:多服务统一启动脚本
容器不能同时前台运行多个服务,编写统一启动脚本
bash
运行
# 进入容器编写脚本
[root@docker01 ~]# docker start magical_germain
[root@docker01 ~]# docker attach magical_germain
[root@e146e20acc64 /]# vi /init.sh
#!/bin/bash
php-fpm -D
nginx -g 'daemon off;'
# 测试脚本
[root@e146e20acc64 /]# sh /init.sh
# 重新提交新版本镜像
[root@docker01 ~]# docker commit e146e20acc64 kod:v2
# 运行镜像,指定启动脚本
[root@docker01 ~]# docker run -d -p 81:80 kod:v2 /bin/bash /init.sh

拓展:集成 MySQL 部署 phpwind 论坛
bash
运行
# 清理旧容器
[root@docker01 ~]# docker rm -f `docker ps -a -q`
# 启动kod:v2容器
[root@docker01 ~]# docker run -it -p 80:80 kod:v2 /bin/bash
# 安装mariadb数据库
[root@aff4c14e2f61 /]# yum -y install mariadb-server
# 初始化数据库
[root@aff4c14e2f61 /]# mysql_install_db --user=mysql --defaults-file=/etc/my.cnf
# 后台启动数据库
[root@aff4c14e2f61 /]# mysqld_safe --defaults-file=/etc/my.cnf &
# 上传phpwind源码解压
[root@docker01 ~]# docker cp phpwind_UTF8_8.7.1.zip silly_morse:/code
[root@aff4c14e2f61 code]# unzip phpwind_UTF8_8.7.1.zip
[root@aff4c14e2f61 code]# mv upload/* .
[root@aff4c14e2f61 code]# chown -R nginx:nginx .
# 创建数据库
[root@aff4c14e2f61 code]# mysql
MariaDB [(none)]> create database phpwind;
MariaDB [(none)]> quit
# 设置root密码
[root@aff4c14e2f61 code]# mysqladmin -uroot password '123456'
# 补充php数据库扩展
[root@aff4c14e2f61 code]# yum -y install php-mysqli
# 修改init.sh,自动启动mysql/php/nginx
[root@aff4c14e2f61 /]# vi /init.sh
#!/bin/bash
mysql_install_db --user=mysql --defaults-file=/etc/my.cnf
mysqld_safe --defaults-file=/etc/my.cnf &
php-fpm -D
nginx -g 'daemon off;'
# 提交phpwind镜像
[root@docker01 ~]# docker commit aff4c14e2f61 phpwind:v1
# 启动论坛容器
[root@docker01 ~]# docker run -d -p 81:80 phpwind:v1 /bin/bash /init.sh
# 时区修复(容器默认UTC,改为上海时区)
[root@docker01 ~]# docker exec -it cf69253defc93 /bin/bash
[root@cf69253defc9 /]# cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
[root@docker01 ~]# docker restart cf69253defc93

9、dockerfile 自动构建 docker 镜像
dockerfile 是镜像自动化构建脚本,替代手动 commit 制作镜像,体积更小、可复用、标准化。
dockerfile 核心指令
表格
指令	作用
FROM	指定基础镜像,文件第一行
MAINTAINER/LABEL	镜像维护人、标签描述
RUN	构建阶段执行 shell 命令
COPY	复制本地文件到镜像(不解压)
ADD	复制文件,tar 包自动解压
WORKDIR	设置容器工作目录(等效 cd)
ENV	定义环境变量
EXPOSE	声明容器暴露端口(仅文档,不自动映射)
VOLUME	声明持久化数据卷
CMD	容器默认启动命令,运行时参数可覆盖
ENTRYPOINT	容器入口脚本,运行参数作为脚本入参,不可覆盖
9.1 Nginx 镜像 dockerfile 示例
dockerfile
# /opt/dockerfile/nginx/Dockerfile
FROM centos:7
# 配置阿里yum源
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
RUN curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
# 安装nginx
RUN yum -y install nginx
# 前台启动nginx,保证容器存活
CMD ["nginx","-g","daemon off;"]

构建 & 运行:
bash
运行
# --network=host 构建时使用宿主机网络拉取yum包
[root@docker01 nginx]# docker build -t centos7_nginx:v2 --network=host /opt/dockerfile/nginx/
# 启动容器,映射88端口
[root@docker01 nginx]# docker run -d -p 88:80 centos7_nginx:v2

9.2 扫雷 Tomcat 案例 dockerfile
文件结构
plaintext
/opt/dockerfile/saolei
├── Dockerfile
└── init.sh

init.sh
bash
运行
#!/bin/bash
/usr/libexec/tomcat/server start

Dockerfile
dockerfile
FROM centos:7
# 本地yum源
RUN curl -o /etc/yum.repos.d/centos7.repo http://192.168.26.111/centos7.repo
RUN yum -y install tomcat unzip
# 下载解压扫雷项目
WORKDIR /var/lib/tomcat/webapps/
RUN curl -o saolei.zip http://192.168.111/software/saolei.zip && unzip saolei.zip && mv saolei ROOT
# 启动脚本放入镜像
ADD init.sh /init.sh
# 声明8080端口
EXPOSE 8080
CMD ["/bin/bash","/init.sh"]

构建运行:
bash
运行
[root@docker01 saolei]# docker build -t centos7_tomcat7:v3 --network=host .
[root@docker01 saolei]# docker run -d -p 8081:8080 centos7_tomcat7:v3
# -P随机端口启动(依赖EXPOSE声明)
[root@docker01 saolei]# docker run -d -P centos7_tomcat7:v4

9.3 可道云 Kod Dockerfile(ENTRYPOINT+ENV+VOLUME)
文件目录
plaintext
/opt/dockerfile/kod
├── Dockerfile
├── init.sh
├── nginx.conf
└── kodexplorer4.40.zip

nginx.conf
nginx
worker_processes  1;
events {
worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   /code;
            index  index.php index.html index.htm;
        }
        location ~ \.php$ {
            root   /code;
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_index index.php;
            fastcgi_param SCRIPT_FILENAME /code$fastcgi_script_name;
            include  fastcgi_params;
        }
    }
}

init.sh
bash
运行
#!/bin/bash
php-fpm -D
# 支持启动时传入密码,无参数使用环境变量
if [ ! -z $1 ];then
SSH_PWD=$1
fi
echo "$SSH_PWD" | passwd --stdin root
/usr/sbin/sshd-keygen
/usr/sbin/sshd
nginx -g 'daemon off;'

Dockerfile
dockerfile
FROM centos:7
# 本地yum源
RUN curl -o /etc/yum.repos.d/centos7.repo http://192.168.26.111/centos7.repo
RUN yum clean all
# 安装依赖
RUN yum -y install nginx php-fpm php-gd php-mbstring unzip openssh-server initscripts
# 修改php运行用户
RUN sed -i '/^user/c user=nginx' /etc/php-fpm.d/www.conf
RUN sed -i '/^group/c group=nginx' /etc/php-fpm.d/www.conf
# 复制nginx配置
COPY nginx.conf /etc/nginx/nginx.conf
# 网站目录
RUN mkdir /code
WORKDIR /code
# 复制kod源码并解压授权
COPY kodexplorer4.40.zip .
RUN unzip kodexplorer4.40.zip && chown -R nginx .
# 全局ssh默认密码
ENV SSH_PWD=123456
# 启动脚本
ADD init.sh /init.sh
# 持久化网站数据
VOLUME /code
# 暴露80网页、22ssh端口
EXPOSE 80 22
# 入口脚本,运行参数传递给init.sh
ENTRYPOINT ["/bin/bash","/init.sh"]

构建与启动测试:
bash
运行
# 构建镜像
[root@docker01 kod]# docker build -t kod:v7 --network=host .
# 自定义ssh密码启动
[root@docker01 kod]# docker run -d -P kod:v7 redhat
# 通过环境变量指定密码
[root@docker01 kod]# docker run -d --env "SSH_PWD=sddfsfdf" -P kod:v7
# 复用已有容器数据卷
[root@docker01 ~]# docker run -d -p 80:80 --volume 卷ID:/code kod:v8
[root@docker01 ~]# docker run -d -p 80:80 --volumes-from 旧容器ID kod:v8

9.4 Dockerfile 优化方案
选用轻量基础镜像(alpine 替代 centos)
多条合并为单个 RUN,减少镜像分层,同时清理 yum 缓存、安装包,减小体积
频繁变更的操作放在 Dockerfile 末尾(缓存复用,构建更快)
使用.dockerignore忽略无关文件,减少构建上下文大小
优化示例:
dockerfile
# 优化前(多层,体积大)
RUN curl xxx
RUN yum install xxx
RUN unzip xxx
RUN rm zip

# 优化后(单一层,安装完立即清理)
RUN curl -o xxx && \
yum -y install xxx && \
unzip xxx && \
rm -rf xxx && \
yum clean all

优化前 kod 镜像 643MB,优化后仅 398MB。
10、docker 镜像分层原理
分层复用:多个镜像共用基础层,节省磁盘、内存
写时复制:只读基础层,容器修改内容仅写入顶层读写层
分层查看命令:
bash
运行
# 查看镜像分层历史
docker image history 镜像名:tag
# 对比容器与基础镜像文件差异
docker diff 容器ID
# 导出分层镜像
docker save -o test.tar test:v1
# 导入镜像,复用本地已有分层不重复下载
docker load -i test.tar

存储驱动默认 overlay2,镜像分层存放路径 /var/lib/docker/overlay2/
11、容器之间互联
--link 链接容器(基于 hosts 域名解析)
格式:--link 源容器名:别名
示例:
bash
运行
# 启动nginx容器
[root@docker01 ~]# docker run -d --name nginx centos7_nginx:v2
# 新建容器链接nginx,使用域名直接访问无需IP
[root@docker01 ~]# docker run -it --link nginx:nginx centos7_nginx:v2 /bin/bash
# 容器内hosts自动写入映射
[root@fcd91dd91c94 /]# cat /etc/hosts
172.17.0.2  nginx 73b680c1debd
# 域名ping通
[root@fcd91dd91c94 /]# ping nginx

实战:Docker 部署 Zabbix 全套容器
bash
运行
# 1. mysql数据库
docker run --name mysql-server -t \
-e MYSQL_DATABASE="zabbix" \
-e MYSQL_USER="zabbix" \
-e MYSQL_PASSWORD="zabbix_pwd" \
-e MYSQL_ROOT_PASSWORD="root_pwd" \
-d mysql:5.7 \
--character-set-server=utf8 --collation-server=utf8_bin

# 2. java网关
docker run --name zabbix-java-gateway -t \
-d zabbix/zabbix-java-gateway:latest

# 3. zabbix服务端
docker run --name zabbix-server-mysql -t \
-e DB_SERVER_HOST="mysql-server" \
-e MYSQL_DATABASE="zabbix" \
-e MYSQL_USER="zabbix" \
-e MYSQL_PASSWORD="zabbix_pwd" \
-e MYSQL_ROOT_PASSWORD="root_pwd" \
-e ZBX_JAVAGATEWAY="zabbix-java-gateway" \
--link mysql-server:mysql \
--link zabbix-java-gateway:zabbix-java-gateway \
-p 10051:10051 \
-d zabbix/zabbix-server-mysql:latest

# 4. web前端
docker run --name zabbix-web-nginx-mysql -t \
-e DB_SERVER_HOST="mysql-server" \
-e MYSQL_DATABASE="zabbix" \
-e MYSQL_USER="zabbix" \
-e MYSQL_PASSWORD="zabbix_pwd" \
-e MYSQL_ROOT_PASSWORD="root_pwd" \
--link mysql-server:mysql \
--link zabbix-server-mysql:zabbix-server \
-p 80:80 \
-d zabbix/zabbix-web-nginx-mysql:latest

12、docker registry 私有仓库
12.1 无认证基础私有仓库
启动 registry 容器
bash
运行
# 持久化镜像目录/opt/myregistry,开机自启
docker run -d -p 5000:5000 --restart=always --name registry -v /opt/myregistry:/var/lib/registry registry

镜像上传完整流程
bash
运行
# 1. 打私有仓库标签
docker tag alpine:latest 192.168.26.201:5000/alpine:latest
# 2. 上传镜像
docker push 192.168.26.201:5000/alpine:latest

http 仓库报错修复
推送报错:server gave HTTP response to HTTPS client
bash
运行
vim /etc/docker/daemon.json
{
  "registry-mirrors": ["https://registry.docker-cn.com"],
  "insecure-registries": ["192.168.26.201:5000"]
}
systemctl restart docker

仓库镜像删除 & 垃圾回收
bash
运行
# 进入容器删除镜像目录
docker exec -it registry /bin/sh
cd /var/lib/registry/docker/registry/v2
rm -rf repositories/alpine
# 垃圾回收释放磁盘
registry garbage-collect /etc/docker/registry/config.yml

12.2 带 Basic 密码认证私有仓库
创建密码文件
bash
运行
yum install httpd-tools -y
mkdir -p /opt/registry-var/auth
htpasswd -Bbn zhongfei 123456 >> /opt/registry-var/auth/htpasswd

带认证启动仓库
bash
运行
docker run -d -p 5000:500 --restart=always \
-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

客户端登录使用
bash
运行
docker login 192.168.26.201:5000
# 拉取私有镜像
docker pull 192.168.26.201:5000/alpine:latest

13、docker 四大网络模式
13.1 bridge(默认桥接)
Docker 默认网络,独立网络命名空间,网段172.17.0.0/16,依靠 iptables 端口转发访问容器。
bash
运行
docker inspect 容器ID

13.2 none(无网络)
完全隔离,无网卡,离线任务使用
bash
运行
docker run -it --network=none test:v1

13.3 host(共享宿主机网络)
容器直接复用宿主机网卡,无需端口映射,性能最优;端口直接占用宿主机端口
bash
运行
docker run -d --network=host kod:v1

13.4 container(共享其他容器网络栈)
两个容器共用一套 IP / 网卡,k8s sidecar 常用
bash
运行
# 先启动基础容器
docker run -d test:v1
# 共享其网络
docker run -it --network container:容器ID test:v1

plaintext

## 方案2:手机端使用
1. 复制全部文本,粘贴到手机备忘录
2. 备忘录选择「导出/分享」,保存为 `.md` 文件即可

## 补充说明
平台限制无法直接提供文件下载链接/附件,以上复制保存是全网通用标准操作,生成的md文件兼容:Typora、VSCode、Git、Notion、语雀、Obsidian等所有主流markdown编辑器。
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐