一 容器
1 Linux 容器的起源
容器的起源可以追溯到1979年 UNIX 系统中提供的chroot命令,容器的最初的设计目标是为了隔离计算机中的各类资源以便降低软件开发、测试阶段的风险,或者充当蜜罐,吸引黑客的攻击,以便监视黑客的行为。最初的容器是以chroot为代表的文件隔离技术,但这并不完美,如主机名、网络、系统进程、用户等都无法隔离
2 名称空间和控制组
为了实现完美的隔离机制,2002年 Linux引入了一种由内核直接提供的全局资源封装的全新隔离机制(名称空间)用来解决隔离的问题,至2009年,Linux内核已经支持了UTSPC、PID、NETWORK、MOUNT等多个名称空间。
Linux解决资源配额的方案是控制组 (Cgroups),它与名称空间一样直接由内核提供功能,用于隔离或者说分配并限制某个进程组能够使用的资源量,包括占用 CPU 时间、内存大小、磁盘 1/0 速度,等等
3 容器的诞生
当文件系统、访问、资源都可以被隔离后,容器已经有它降生所需的全部条件,Linux内核开始提供Cgroups的同一时间就马上发布了名为 LXC的系统级虚拟化功能
LXC 带着令人瞩目的光环登场,可惜的是,LXC 在设定自己的发展目标时,被前辈们的影响所局限住。LXC 眼中的容器是一种封装系统的轻量级虚拟机。这种局限的思想也决定了LXC不可能形成今天的容器生态的,所以,接下来舞台的聚光灯终于落到了 Docker 身上。
二 docker
1 概述
2013年3月,一个名为 Docker 的项目宣布开源
当时的人们并没有意识到这款软件将要带来怎样的技术变革
它的出现促使“容器”从一个阳春白雪的只流传于极客口中的技术词汇,逐渐走向整个IT舞台的中央短短数年时间,就已成为开发、测试、部署等各个环节都难以或缺的基础支撑。是什么样的魔力让 Docker 可以从一问世就惊艳世间
2 理念
促使 Docker的一问世就惊艳世间的,不是什么黑科技式的秘密武器,而是其符合历史潮流的创意与设计理念,还有充分开放的生态环境。
早期的容器技术是一种封装系统的轻量级虚拟化,Docker眼中“容器技术”是一种以应用为核心,对程序文件、运行时环境、软件依赖包都可以封装打包、部署的技术手段
Docker 的容器中没有系统
2014年,Docker开源了自己用 Golang开发的 Libcontainer
2015年,在Docker的主导和倡议下,多家公司联合制定“开放容器交互标准”(0CI),这是一个关于容器格式和运行时的规范文件,其中包含:
- 运行时标准(RUNTIME-SPEC)
- 容器镜像标准(IMAGE-SPEC)
- 镜像分发标准(DISTRIBUTION-SPEC)
3 三大概念
容器:容器是一个运行在隔离环境中的程序
镜像:镜像是只读的模板,包含了创建容器所需的所有文件和配置信息
仓库:仓库是用来存储、分发、管理镜像的地方
三 安装部署
1 配置Yum仓库
把 docker 软件包添加到跳板机的自定义 yum 仓库中
[root@docker ~]# yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
主机名 | IP地址 | 最低配置 |
---|---|---|
docker-0001 | 192.168.1.31 | 2CPU,4G内存 |
docker-0002 | 192.168.1.32 | 2CPU,4G内存 |
2 系统管理命令
命令 | 说明 |
---|---|
docker version | 查看服务器与客户端版本 |
docker info | 查看 docker 服务配置信息 |
3 安装部署
# 开启路由转发
[root@docker ~]# echo 'net.ipv4.ip_forward = 1' >>/etc/sysctl.conf
[root@docker ~]# sysctl -p
[root@docker ~]# dnf install -y docker-ce
[root@docker ~]# systemctl enable --now docker
# 查看服务器与客户端版本
[root@docker ~]# docker version
Client: Docker Engine - Community
Version: 20.10.10
... ...
Server: Docker Engine - Community
Engine:
Version: 20.10.10
4 添加镜像加速
[root@docker ~]# vim /etc/docker/daemon.json
{
"registry-mirrors": ["这里配置镜像仓库加速器地址"],
"insecure-registries":[]
}
[root@docker ~]# systemctl restart docker
# 查看 docker 服务配置信息
[root@docker ~]# docker info
... ...
Insecure Registries:
127.0.0.0/8
Registry Mirrors:
https://镜像仓库加速器/
Live Restore Enabled: false
四 镜像
1 概述
- 镜像是创建容器的核心
- 镜像使用CoW技术
- 镜像采用分层设计
- 镜像始终都是只读的
如何创建容器?
首先使用 Cow 为镜像创建一个读写层,容器在读写层运行
这种方式可以让一个镜像创建无数个容器
2 获取镜像
镜像可以从官方镜像仓库下载,也可以自己制作
官方镜像仓库:https://hub.docker.com
从官方下载较慢,可以使用国内的镜像站加速
添加配置文件: /etc/docker/daemon.json
{
"reqistry-mirrors":["这里配置镜像加速器地址”]
"insecure-registries":[ ]
}
[root@docker ~]# vim /etc/docker/daemon.json
{
"registry-mirrors": ["这里配置镜像仓库加速器地址"],
"insecure-registries":[]
}
[root@docker ~]# systemctl restart docker
# 查看 docker 服务配置信息
[root@docker ~]# docker info
... ...
Insecure Registries:
127.0.0.0/8
Registry Mirrors:
https://镜像仓库加速器/
Live Restore Enabled: false
3 镜像管理命令
镜像管理命令 | 说明 | 备注 |
---|---|---|
docker images | 查看本机镜像 | |
docker pull 镜像名称:标签 | 下载镜像 | |
docker save 镜像名称:标签 -o 备份文件名称 | 备份镜像为tar包 | 备份文件是 tar 格式 |
docker load -i 备份文件名称 | 导入备份的镜像文件 | 备份文件 tar 或 tar.xx 格式 |
docker history 镜像名称:标签 | 查看镜像的制作历史 |
镜像管理案例
pull、images、history
# 下载 busybox:latest 镜像
[root@docker ~]# docker pull busybox:latest
# 查看本机镜像
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest 66ba00ad3de8 5 weeks ago 4.87MB
# 查看镜像的制作历史
[root@docker ~]# docker history busybox:latest
IMAGE CREATED CREATED BY SIZE
b539af69bc01 9 days ago /bin/sh -c #(nop) CMD ["sh"] 0B
<missing> 9 days ago /bin/sh -c #(nop) ADD file:069460fea045… 4.86MB
指定镜像的方法
- 每一个镜像都对应唯一的镜像 id
- 镜像名称 + 标签 = 唯一
- 每一个镜像都有标签,默认标签 latest我们在调用镜像的时候,如果没有指定标签也是 latest
镜像的备份与恢复
save、load
# 备份 rockylinux:8.5 镜像为 tar 包
[root@docker ~]# docker save busybox:latest -o busybox.tar
# 使用备份文件恢复镜像
[root@docker ~]# docker load -i myos.tar.xz
Loaded image: rockylinux:8.5
Loaded image: myos:8.5
Loaded image: myos:php-fpm
Loaded image: myos:nginx
Loaded image: myos:httpd
Loaded image: myos:latest
# 查看本机镜像
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
myos php-fpm 7124977c0b21 12 days ago 275MB
myos latest 1de38c85c2d1 3 weeks ago 4.67MB
myos nginx 5e45400d8e76 3 weeks ago 274MB
myos httpd 9245e660f88f 3 weeks ago 299MB
myos 8.5 621bfd7f9b46 3 weeks ago 249MB
busybox latest 66ba00ad3de8 5 weeks ago 4.87MB
rockylinux 8.5 210996f98b85 14 months ago 205MB
[root@docker-0001 ~]# docker load -i myos.tar.xz
[root@docker-0001 ~]# docker save rockylinux:8.5 -o rockylinux.tar
[root@docker-0001 ~]# scp rockylinux.tar 192.168.1.32:/root/
#-------------------------------------------------------------------#
[root@docker-0001 ~]# docker load -i rockylinux.tar
[root@docker-0001 ~]# docker history rockylinux:8.5
五 容器管理
1 容器管理命令
容器管理命令 | 说明 |
---|---|
docker run -it(d) 镜像名称:标签 | 创建容器 |
docker ps | 查看容器的信息 |
docker inspect 镜像名称|容器名称 | 查询(容器/镜像)的详细信息 |
docker [start|stop|restart] 容器id | 启动、停止、重启容器 |
docker exec -it 容器ID 启动命令 | 在容器内执行命令 |
docker cp 路径1 路径2 | 拷贝文件:路径格式(本机路径、容器ID/路径) |
2 容器管理案例
run
查看 run 的参数
- docker help run
- man docker-run
docker run 常用参数
- 参数 -i 交互式
- 参数 -t 分配终端
- 参数 -d 后台运行
- 参数 --name 容器名字
- 参数 --rm 容器结束后自动删除
- 转入后台快捷键 (ctrl-p + ctrl-g)
# 创建一个容器
[root@docker ~]# docker run -it myos:8.5
[root@3aa1df05b795 /]# hostname
3aa1df05b795
[root@3aa1df05b795 /]# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 15:13 pts/0 00:00:00 /bin/bash
root 19 1 0 15:13 pts/0 00:00:00 ps -ef
[root@3aa1df05b795 /]# ifconfig eth0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@3aa1df05b795 /]# exit
# 创建后台容器
[root@docker ~]# docker run -itd myos:httpd
6d6884244a995791f8171efa3ce81be1e9e51bedf25c3a5a67bac8bb7bc019b0
# 创建名为web1的后台容器
[root@docker ~]# docker run -itd --name web1 myos:httpd
14b669a75a95e9ba590c37137abc9d828d2c769d46f69c35fb0e8cc98cc544c4
ps
docker ps 常用参数
- -a 显示所有容器
- -p 只显示ID
# 查询容器状态
[root@docker ~]# docker ps
CONTAINER ID IMAGE ... ... STATUS PORTS NAMES
14b669a75a95 myos:httpd ... ... Up 25 minutes 80/tcp web1
6d6884244a99 myos:httpd ... ... Up 25 minutes 80/tcp hawking
[root@docker ~]# docker ps -a
CONTAINER ID IMAGE ... ... STATUS PORTS NAMES
14b669a75a95 myos:httpd ... ... Up 25 minutes 80/tcp web1
6d6884244a99 myos:httpd ... ... Up 25 minutes 80/tcp hawking
47ded92f442f myos:8.5 ... ... Exited (0) yonath
[root@docker ~]# docker ps -aq
14b669a75a95
6d6884244a99
47ded92f442f
start、stop、restart
[root@docker ~]# docker ps -a
CONTAINER ID IMAGE ... ... STATUS PORTS NAMES
14b669a75a95 myos:httpd ... ... Up 25 minutes 80/tcp web1
6d6884244a99 myos:httpd ... ... Up 25 minutes 80/tcp hawking
47ded92f442f myos:8.5 ... ... Exited (0) yonath
# 停止容器
[root@docker ~]# docker stop web1 6d6884244a99
web1
6d6884244a99
[root@docker ~]# docker ps -a
CONTAINER ID IMAGE ... ... STATUS PORTS NAMES
14b669a75a95 myos:httpd ... ... Exited (0) web1
6d6884244a99 myos:httpd ... ... Exited (0) hawking
47ded92f442f myos:8.5 ... ... Exited (0) yonath
# 启动容器
[root@docker ~]# docker start web1
web1
[root@docker ~]# docker ps -a
CONTAINER ID IMAGE ... ... STATUS PORTS NAMES
14b669a75a95 myos:httpd ... ... Up 6 seconds 80/tcp web1
6d6884244a99 myos:httpd ... ... Exited (0) hawking
47ded92f442f myos:8.5 ... ... Exited (0) yonath
# 重启容器
[root@docker ~]# docker restart 6d6884244a99
6d6884244a99
[root@docker ~]# docker ps -a
CONTAINER ID IMAGE ... ... STATUS PORTS NAMES
14b669a75a95 myos:httpd ... ... Up 18 seconds 80/tcp web1
6d6884244a99 myos:httpd ... ... Up 3 seconds 80/tcp hawking
47ded92f442f myos:8.5 ... ... Exited (0) yonath
inspect
# 查询镜像的详细信息
[root@docker ~]# docker inspect myos:httpd
{ ......
"Cmd": [
"httpd",
"-DFOREGROUND"
],
......
}
# 查询容器的详细信息
[root@docker ~]# docker inspect 6d6884244a99 web1
[
{ ... ...
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
... ...
exec、cp
拷贝文件
- 上传:docker cp 本机文件路径 容器id:容器内路径
- 下载:docker cp 容器id:容器内路径 本机文件路径
# 在容器内执行非交互命令
[root@docker ~]# docker exec -it web1 /bin/ls
index.html info.php
# 在容器内执行交互命令
[root@docker ~]# docker exec -it web1 /bin/bash
[root@487e19bb4ca3 ~]# exit
# 从容器内拷贝文件出来
[root@docker ~]# docker cp web1:/etc/httpd/conf/httpd.conf ./
[root@docker ~]# sed -ri "s,(Listen )80,\18080," httpd.conf
# 把文件拷贝到容器内
[root@docker ~]# docker cp httpd.conf web1:/etc/httpd/conf/
# 重启容器
[root@docker ~]# docker restart web1
# 查询容器详细信息
[root@docker ~]# docker inspect web1
{
"Networks": {
"bridge": {
"IPAddress": "172.17.0.2",
......
}
[root@docker ~]# curl http://172.17.0.2:8080/
Welcome to The Apache.
3 其他管理命令
管理命令 | 说明 |
---|---|
docker rm 容器ID | 删除容器 |
docker logs 容器ID | 查看容器日志 |
docker tag 镜像ID:标签 镜像名称:新的标签 | 创建新的镜像名称和标签 |
docker rmi 镜像名称:标签 | 删除镜像(必须先删除该镜像启动的所有容器) |
管理命令案例
rm、logs
# 删除容器
[root@docker ~]# docker rm 47ded92f442f
# 强制删除容器
[root@docker ~]# docker rm -f web1
# 删除所有容器
[root@docker ~]# docker rm -f $(docker ps -aq)
# 创建容器
[root@docker ~]# docker run -itd --name web myos:nginx
# 访问容器
[root@docker ~]# docker inspect web |grep IPAddress
[root@docker ~]# curl http://172.17.0.2/info.php
# 查看容器日志
[root@docker ~]# docker logs web
2023/01/17 15:51:49 [error] 6#0: *1 open() "/usr/local/nginx/html/info.php" failed (2: No such file or directory), client: 172.17.0.1, server: localhost, request: "GET /info.php HTTP/1.1", host: "172.17.0.2"
rmi、tag
# 删除一个镜像
[root@docker ~]# docker rmi busybox:latest
Untagged: busybox:latest
# 已经创建容器的镜像无法删除
[root@docker ~]# docker rmi -f myos:nginx
Untagged: myos:nginx
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
myos php-fpm 7124977c0b21 12 days ago 275MB
myos latest 1de38c85c2d1 3 weeks ago 4.67MB
<none> <none> 5e45400d8e76 3 weeks ago 274MB
myos httpd 9245e660f88f 3 weeks ago 299MB
myos 8.5 621bfd7f9b46 3 weeks ago 249MB
rockylinux 8.5 210996f98b85 14 months ago 205MB
# 给镜像设置一个新的名称标签
[root@docker ~]# docker tag 5e45400d8e76 myos:nginx
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
myos php-fpm 7124977c0b21 12 days ago 275MB
myos latest 1de38c85c2d1 3 weeks ago 4.67MB
myos nginx 5e45400d8e76 3 weeks ago 274MB
myos httpd 9245e660f88f 3 weeks ago 299MB
myos 8.5 621bfd7f9b46 3 weeks ago 249MB
rockylinux 8.5 210996f98b85 14 months ago 205MB
六 自定义镜像
- 镜像采用分层设计
- 创建读写层
- 修改配置
- 重新打包
简单镜像制作
# 使用基础镜像创建一个容器
[root@docker ~]# docker run -itd --name linux rockylinux:8.5
# 删除容器内的Yum配置文件
[root@docker ~]# docker exec -it linux rm -rf /etc/yum.repos.d
# 拷贝宿主机的Yum配置文件到容器内
[root@docker ~]# docker cp /etc/yum.repos.d linux:/etc/
# 在容器内安装工具软件包
[root@docker ~]# docker exec -it linux dnf install -y net-tools vim-enhanced tree bash-completion iproute procps-ng psmisc
# 清理缓存文件
[root@docker ~]# docker exec -it linux dnf clean all
# 停止容器
[root@docker ~]# docker stop linux
# 把容器制作成镜像
[root@docker ~]# docker commit linux mylinux:latest
sha256:7a4449e20f4c59d1f6c4db838b4724cbf63c8f4195513c5f17d053c7752891d5
# 查看新制作的镜像
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mylinux latest b64da40467ae 3 seconds ago 249MB
rockylinux 8.5 210996f98b85 13 months ago 205MB
# 删除制作镜像的容器
[root@docker ~]# docker rm -f linux
linux
七 容器部署应用
在容器中安装部署 apache 服务
如何在容器内启动服务?
- 由于容器内没有 systemd,参考服务文件手工执行启动程序
- 服务文件路径 /usr/lib/systemd/system/httpd.service
- 查看服务文件,设置环境变量执行服务启动程序
- 如果没有 service文件,参考官方手册配置、启动服务
1 安装部署 apache 服务
# 删除所有容器
[root@docker ~]# docker rm -f $(docker ps -aq)
# 创建一个名为 myweb 的容器
[root@docker ~]# docker run -it --rm --name myweb mylinux:latest
#-----------------------------------------------------------
# 在容器内安装部署 apache
[root@a7f9d0c3e3e2 /]# dnf install -y httpd
[root@a7f9d0c3e3e2 /]# echo "Hello World ." >/var/www/html/index.html
[root@a7f9d0c3e3e2 /]# cat /usr/lib/systemd/system/httpd.service
[root@a7f9d0c3e3e2 /]# export LANG=C
[root@a7f9d0c3e3e2 /]# /usr/sbin/httpd -DFOREGROUND
# 在另一个终端完成访问验证
2 为 apache 添加解析 php 文件支持
# ctrl + c 终止 httpd 服务运行
[root@a7f9d0c3e3e2 /]# dnf install -y php
[root@a7f9d0c3e3e2 /]# vim /etc/httpd/conf.modules.d/00-mpm.conf
11: LoadModule mpm_prefork_module ... ... # 去掉注释
17: # LoadModule mpm_event_module ... ... # 注释配置
[root@a7f9d0c3e3e2 /]# /usr/sbin/httpd -DFOREGROUND
# 服务不要关闭,在其他终端完成测试
3 验证配置
# 在另一个终端拷贝 public/info.php 到 docker 主机
[root@docker ~]# docker cp info.php myweb:/var/www/html/
[root@docker ~]# curl http://172.17.0.2/info.php
<pre>
Array
(
[REMOTE_ADDR] => 172.17.0.1
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.61.1
[REQUEST_URI] => /info.php
)
php_host: 616e75df56ae
1229
八 容器服务原理
1 什么是上帝进程?
简单的说就是系统创建之初产生的第一个进程
2 特点
- 没有父进程,PID = 1
- 是所有程序的根进程
- 上帝进程死亡系统实例也就关闭了
3 容器有没有上帝进程?
容器的启动进程就是上帝进程
如果容器的启动进程关闭等同于容器关闭
4 前台服务 VS后台服务?
前台服务是占有控制终端的进程,可以在终端与用户交互式的访问与操作,一旦终端关闭,这个进程也随之消失。
后台进程也叫守护进程,不受终端控制,它不需要交互;后台进程的本质是向系统托管进程服务