容器技术的起源

1. Linux容器的起源
  • 容器的起源可以追溯到1979年unix系统中提供的chroot命令 , 容器的最初的设计目标是为了隔离计算机中的各类资源 , 以便降低软件开发 , 测试阶段的风险 , 或者充当米关 ,吸引黑客的攻击 , 以便监视黑客的行为
  • 最初的容器是以chroot为代表的文件隔离技术 , 但这并不完美 , 如主机名, 网络 , 系统进程 , 用户等都无法隔离
2. 名称空间与控制组
  • 为了实现完美的隔离机制,2002年 Linux引入了一种由内核直接提供的全局资源封装的全新隔离机制(名称空间)用来解决隔离的问题,至2009年,Linux内核已经支持了UTS、 IPC、PID、NETWORK、MOUNT等多个名称空间。
  • Linux 解决资源配额的方案是控制组(Cgroups),它与名称空间一样直接由内核提供功能,用于隔离或者说分配并限制某个进程组能够使用的资源量,包括占用CPU时间、内存大小、磁盘1/0速度,等等
3. 容器诞生
  • 当文件系统 ,访问 , 资源都可以被隔离后 , 容器已经有它降生所需的全部条件 , Linux内核开始提供Cgroups的同一时间 , 就马上发布了名为 LXC的系统级虚拟化功能
  • LXC眼中的容器是一种封装系统的轻量级虚拟机器 , 这种局限的思想也决定了LXC不可能形成今天的容器生态
4. Docker概述
  • 2013年3月 , Docker项目宣布开源
  • 早期的容器技术是一种封装系用的轻量级虚拟化 , Docker眼中的容器技术是一种以应用为核心 , 对程序文件 , 运行环境 ,软件依赖包都可以封装打包 , 部署的技术手段
  • Docker 的容器中没有系统
  • 2015年 , Docker联合多家公司联合制定了 开放容器交互标准 (OCI) , 这是一个关于容器格式和运行时的规范文件 , 其中包括 :
  • 运行时标准 (RUNTIME-SPEC)
  • 容器镜像标准 (IMAGE-SPEC)
  • 镜像分发标准 (DISTRIBUTION-SPEC)
4.1三大概念
  1. 容器 : 容器是一个运行在隔离环境中的程序
  2. 镜像 : 镜像是只读的模板 . 包含了创建容器所需的所有文件和配置信息
  3. 仓库 : 仓库是用来存储 , 分发 , 管理镜像的地方

docker的安装部署

  • 需要64位操作系统
  • 内核版本 > 2.6.32

主机名

IP地址

最低配置

docker-0001

192.168.1.31

2CPU,4G内存

docker-0002

192.168.1.32

2CPU,4G内存

1. 配置自定义yum仓库
  • 华为云提供的Yum仓库中没有docker软件包
  • 向自定义的Yum仓库中添加 docker软件包
[root@ecs-proxy s4]# rsync -av docker/ /var/localrepo/docker/

[root@ecs-proxy s4]# createrepo --update /var/localrepo
2. 开启路由转发
  • 开启Docker时需要开启路由转发的原因是为了让Docker能够根据虚拟机的IP地址为其所有的Docker容器分配虚拟IP。路由转发是Linux内核的一个功能,它允许系统转发从一个网络接口收到的数据包到另一个网络接口。在Docker的场景中,当Docker启动时,它会创建一个名为docker0的虚拟网桥,并为每个容器分配一个虚拟IP地址。这些虚拟IP地址与宿主机上的物理网络接口不同,因此需要通过路由转发来实现容器与宿主机以及容器之间的网络通信
[root@docker ~]# echo 'net.ipv4.ip_forward = 1' >>/etc/sysctl.conf

[root@docker ~]# sysctl -p
3. 安装 docker 软件包
[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

镜像管理

1. 镜像概述
  • 镜像是创建容器的核心
  • 镜像使用CoW技术
  • Copy-on-Write(简称CoW)是一种计算机程序设计领域的优化策略,也是一种特殊的文件复制技术。其核心思想是,如果有多个调用者(callers)同时请求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的。此作法主要的优点是如果调用者没有修改该资源,就不会有副本(private copy)被创建,因此多个调用者只是读取操作时可以共享同一份资源。
  • 镜像采用分层设计
  • docker history 查看
  • 镜像使用都是只读
2. 如何让创建容器
  • 使用CoW为镜像创建一个读写层 , 容器在读写层运行
  • 这种方式可以让一个镜像创建无数个容器
3. 获取镜像
  • 镜像可以从官方镜像仓库下载 , 也可以自己制作
  • 官方镜像仓库
  • 从官方下载较慢 , 可以使用国内的镜像站加速
  • 添加配置文件 : /etc/docker/daemon.json
    {
    “registry-mirrors”: [“这里配置镜像加速器地址”] ,
    “insecure-registries”: []
    }
  • 使用华为云的容器 - 容器镜像服务SWR -加速器地址 : https://08fd2eac6380f2990f29c01e5fdf3480.mirror.swr.myhuaweicloud.com
#使用华为的镜像加速器
[root@docker ~]# vim /etc/docker/daemon.json
{
    "registry-mirrors": ["https://08fd2eac6380f2990f29c01e5fdf3480.mirror.swr.myhuaweicloud.com"],
    
    "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
4. 下载镜像
4.1镜像管理命令
  • docker images 查看本机镜像
  • docker pull 镜像名称:标签 下载镜像
  • docker push 镜像名称:标签 上传镜像
  • docker save 镜像名称:标签 -o 文件名 备份镜像为tar包
  • docker load -i 备份文件名称 导入备份的镜像文件
  • docker history 镜像名称:标签 查看镜像的制作历史
4.2操作
  • 在华为云 容器-镜像中心 可搜索
  • latest 代表最新版本
# 下载 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
# 备份 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

或 , 从 /lin../s4/public/ myos.tar.xz到 192.168.1.31进行load还原 , 完成学习环境.

容器管理

1. 创建容器
  • 使用docker run 命令创建容器
  • docker run -参数 镜像名称:镜像标签 [手工指定启动命令]
  • 查看run参数
  • docker help run
  • man dokcer-run
1.1docker run 常用参数
  • 参数 -i 交互式
  • 参数 -t 分配终端
  • 参数 -d 后台运行
  • 参数 -name 容器名称
  • 参数 -rm 容器结束后自动删除
  • 转入后台快捷键 ctrl-p + ctrl-q
2. 容器管理命令

容器管理命令

说明

docker run -it(d) 镜像名称:标签

创建容器

docker ps

查看容器的信息

docker inspect 镜像名称|容器名称

查询(容器/镜像)的详细信息

docker [start|stop|restart] 容器id

启动、停止、重启容器

docker exec -it 容器ID 启动命令

在容器内执行命令

docker cp 路径1 路径2

拷贝文件:路径格式(本机路径、容器ID/路径)

2.1 操作
  • run 创建容器
# 创建一个容器
[root@docker ~]# docker run -it myos:8.5

[root@3aa1df05b795 /]# hostname

[root@3aa1df05b795 /]# ps -ef

[root@3aa1df05b795 /]# ifconfig eth0

[root@3aa1df05b795 /]# exit

# 创建后台容器
[root@docker ~]# docker run -itd myos:httpd

# 创建名为web1的后台容器
[root@docker ~]# docker run -itd --name web1 myos:httpd
  • ps 查看容器
  • CONTAINER ID 容器的ID
  • IMAGE 容器的源
  • COMMAND 是容器的上帝进程
# 查询容器状态
[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 容器内执行任务 , 复制文件
# 在容器内执行非交互命令
[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.
2.2 其他管理命令

管理命令

说明

docker rm 容器ID

删除容器

docker logs 容器ID

查看容器日志

docker tag 镜像ID:标签 镜像名称:新的标签

创建新的镜像名称和标签

docker rmi 镜像名称:标签

删除镜像(必须先删除该镜像启动的所有容器)

2.3 操作
  • 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

# 给镜像设置一个新的名称标签
[root@docker ~]# docker tag 5e45400d8e76 myos:nginx

[root@docker ~]# docker images

镜像与服务

  • 基于原始镜像可以创建新的镜像 , 原始镜像一般是官方提供的
1. 自定义镜像
  • 镜像采用分层设计
  • 创建读写层
  • 修改配置
  • 重新打包
1.1 使用commit制作新镜像
  • 使用现有镜像启动容器 , 在该容器基础上修改
# 使用基础镜像创建一个容器
[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
2. 容器内部部署应用
  • 目标 : 在容器中安装部署apache服务
  1. 由于容器内没有 systemd , 参考服务文件手工执行启动程序
  2. 服务文件路径 /usr/lib/systemd/system/httpd.service
  3. 查看服务文件 , 设置环境变量执行服务启动程序
  4. 如果没有 service文件 , 参考官方手册配置 , 启动服务
2.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

#启动httpd服务 , 强制Apache在前台启动
[root@a7f9d0c3e3e2 /]# /usr/sbin/httpd -DFOREGROUND
# 在另一个终端完成访问验证
2.2 为Apache 添加解析 php文件的支持
# ctrl + c 终止 httpd 服务运行

#安装php软件包
[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
# 服务不要关闭,在其他终端完成测试
2.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
3. 容器服务原理
  • 上帝进程 : 系统创建之初产生的第一个进程
  • 没有父进程 , PID==1
  • 是所有进程的根进程
  • 上帝进程死亡系统实例也就关闭了
  • 容器的启动进程就是上帝进程
  • 如果容器的启动进程关闭等同于容器关闭
  • 前台鼓舞是占有控制终端的进程 , 可以在终端与用户交互式的访问与操作 ,一旦终端关闭 , 这个进程也随之消失
  • 后台进程也叫守护进程 , 不受终端控制 , 它不需要交互 ;后台进程的本质是向系统托管进程服务