Docker容器技术基础
Docker基础
容器(Container)
- 容器是一种基础工具;泛指任何可以用于容纳其他物品的工具,可以部分或完全封闭,被用于容纳、储存、运输物品;物体可以被放置在容器中,而容器则可以保护内容物;
- 人类使用容器的历史至少有十万年,甚至可能有数百万年的历史;
- 容器的类型
- 瓶 - 指口部比腹部窄小、颈长的容器
- 罐 - 指那些开口较大、一般为近圆筒形的器皿
- 箱 - 通常是立方体或圆柱体。形状固定
- 篮 - 以条状物编织而成
- 桶 - 一种圆柱形的容器
- 袋 - 柔性材料制成的容器,形状会受内容物而变化
- 瓮 - 通常是指陶制,口小肚大的容器
- 碗 - 用来盛载食物的容器
- 柜 - 指一个由盒组成的家具
- 鞘 - 用于装载刀刃的容器
传统虚拟化与容器的区别
虚拟化分为以下两类:
- 主机级虚拟化
- 全虚拟化
- 半虚拟化
- 容器级虚拟化
容器分离开的资源:
- UTS(主机名与域名)
- Mount(文件系统挂载树)
- IPC
- PID进程树
- User
- Network(tcp/ip协议栈)
Linux容器技术
Linux容器其实并不是什么新概念。最早的容器技术可以追遡到1982年Unix系列操作系统上的chroot工具(直到今天,主流的Unix、Linux操作系统仍然支持和带有该工具)。
Linux Namespaces
命名空间(Namespaces)是Linux内核针对实现容器虚拟化而引入的一个强大特性。
每个容器都可以拥有自己独立的命名空间,运行其中的应用都像是在独立的操作系统中运行一样。命名空间保证了容器间彼此互不影响。
namespaces | 系统调用参数 | 隔离内容 | 内核版本 |
---|---|---|---|
UTS | CLONE_NEWUTS | 主机名和域名 | 2.6.19 |
IPC | CLONE_NEWIPC | 信号量、消息队列和共享内存 | 2.6.19 |
PID | CLONE_NEWPID | 进程编号 | 2.6.24 |
Network | CLONE_NEWNET | 网络设备、网络栈、端口等 | 2.6.29 |
Mount | CLONE_NEWNS | 挂载点(文件系统) | 2.4.19 |
User | CLONE_NEWUSER | 用户和用户组 | 3.8 |
CGroups
控制组(CGroups)是Linux内核的一个特性,用来对共享资源进行隔离、限制、审计等。只有能控制分配到容器的资源,Docker才能避免多个容器同时运行时的系统资源竞争。
控制组可以提供对容器的内存、CPU、磁盘IO等资源进行限制。
CGroups能够限制的资源有:
- blkio:块设备IO
- cpu:CPU
- cpuacct:CPU资源使用报告
- cpuset:多处理器平台上的CPU集合
- devices:设备访问
- freezer:挂起或恢复任务
- memory:内存用量及报告
- perf_event:对cgroup中的任务进行统一性能测试
- net_cls:cgroup中的任务创建的数据报文的类别标识符
具体来看,控制组提供如下功能:
- 资源限制(Resource Limitting)组可以设置为不超过设定的内存限制。比如:内存子系统可以为进行组设定一个内存使用上限,一旦进程组使用的内存达到限额再申请内存,就会发出Out of Memory警告
- 优先级(Prioritization)通过优先级让一些组优先得到更多的CPU等资源
- 资源审计(Accounting)用来统计系统实际上把多少资源用到合适的目的上,可以使用cpuacct子系统记录某个进程组使用的CPU时间
- 隔离(Isolation)为组隔离命名空间,这样一个组不会看到另一个组的进程、网络连接和文件系统
- 控制(Control)挂起、恢复和重启等操作
安装Docker后,用户可以在/sys/fs/cgroup/memory/docker/
目录下看到对Docker组应用的各种限制项,包括
[root@localhost ~]# cd /sys/fs/cgroup/memory/
[root@localhost memory]# ls
cgroup.clone_children memory.kmem.slabinfo memory.memsw.limit_in_bytes memory.swappiness
cgroup.event_control memory.kmem.tcp.failcnt memory.memsw.max_usage_in_bytes memory.usage_in_bytes
cgroup.procs memory.kmem.tcp.limit_in_bytes memory.memsw.usage_in_bytes memory.use_hierarchy
cgroup.sane_behavior memory.kmem.tcp.max_usage_in_bytes memory.move_charge_at_immigrate notify_on_release
memory.failcnt memory.kmem.tcp.usage_in_bytes memory.numa_stat release_agent
memory.force_empty memory.kmem.usage_in_bytes memory.oom_control system.slice
memory.kmem.failcnt memory.limit_in_bytes memory.pressure_level tasks
memory.kmem.limit_in_bytes memory.max_usage_in_bytes memory.soft_limit_in_bytes user.slice
memory.kmem.max_usage_in_bytes memory.memsw.failcnt memory.stat
用户可以通过修改这些文件值来控制组限制Docker应用资源。
LXC
通过传统方式使用容器功能的话需要我们自己写代码去进行系统调用来实现创建内核,实际上拥有此能力的人廖廖无几。而LXC(LinuX Container)把容器技术做得更加易用,把需要用到的容器功能做成一组工具,从而极大的简化用户使用容器技术的麻烦程度。
LXC是最早一批真正把完整的容器技术用一组简易使用的工具和模板来极大的简化了容器技术使用的一个方案。
LXC虽然极大的简化了容器技术的使用,但比起直接通过内核调用来使用容器技术,其复杂程度其实并没有多大降低,因为我们必须要学会LXC的一组命令工具,且由于内核的创建都是通过命令来实现的,通过批量命令实现数据迁移并不容易。其隔离性也没有虚拟机那么强大。
后来就出现了docker,所以从一定程度上来说,docker就是LXC的增强版。
docker基本概念
docker是容器技术的一个前端工具,容器是内核的一项技术,docker只是把这一项技术的使用得以简化,使之普及而已。
LXC进行大规模创建容器很难,想在另一台主机上复刻一个一模一样的容器也很难,而docker就是从这方面着手去找解决方案。所以docker早期的版本其核心就是一个LXC,docker对其进行了二次封装,功能的实现是通过LXC做容器管理引擎,但是在创建容器时,不再是像LXC一样用模板去现场安装,而是事先通过一种类似镜像技术,就像在KVM中一样,将一个操作系统打包成一个镜像,然后将这个镜像拷贝到目标主机上直接部署启动。
我们可以尝试着把一个操作系统用户空间需要用到的所有组件,事先准备、编排好,编排好以后整体打包成一个文件,这个文件我们称其为镜像文件(image)。
docker的镜像文件是放在一个集中统一的互联网仓库中的,把一些人们常用的镜像文件放在互联网仓库中,比如最小化的centos系统,有时我们需要在操作系统上安装一些应用,比如nginx,我们就可以在一个最小化的centos系统中安装一个nginx,然后将其打包成镜像,将其放在互联网仓库中,当人们想启动一个容器的时候,docker会到这个互联网仓库中去下载我们需要的镜像到本地,并基于镜像来启动容器。
自docker 0.9版本起,docker除了继续支持LXC外,还开始引入自家的libcontainer,试图打造更通用的底层容器虚拟化库。如今的docker基本上都已经是使用libcontainer而非LXC了。
从操作系统功能上看,docker底层依赖的核心技术主要包括Linux操作系统的命名空间、控制组、联合文件系统和Linux虚拟网络支持。
docker工作方式
为了使容器的使用更加易于管理,docker采取一个用户空间只跑一个业务进程的方式,在一个容器内只运行一个进程,比如我们要在一台主机上安装一个nginx和一个tomcat,那么nginx就运行在nginx的容器中,tomcat运行在tomcat的容器中,二者用容器间的通信逻辑来进行通信。
LXC是把一个容器当一个用户空间使用,当虚拟机一样使用,里面可以运行N个进程,这就使得我们在容器内去管理时极为不便,而docker用这种限制性的方式,在一个容器中只运行一个进程的方式,使得容器的管理更加方便。
使用docker的优劣:
- 删除一个容器不会影响其他容器
- 调试不便,占空间(每个容器中都必须自带调试工具,比如ps命令)
- 分发容易,真正意义上一次编写到处运行,比java的跨平台更彻底
- 部署容易,无论底层系统是什么,只要有docker,直接run就可以了
- 分层构建,联合挂载
在容器中有数据称作有状态,没有数据称作无状态。在容器的使用中,我们应以有状态为耻,以无状态为荣。数据不应该放在容器中,而应放置于外部存储中,通过挂载到容器中从而进行数据的存储。
docker容器编排
当我们要去构建一个lnmp架构的时候,它们之间会有依赖关系,哪个应用应该在什么时候启动,在谁之前或之后启动,这种依赖关系我们应该要事先定义好,最好是按照一定的次序实现,而docker自身没有这个功能,所以我们需要一个在docker的基础上,能够把这种应用程序之间的依赖关系、从属关系、隶属关系等等反映在启动、关闭时的次序和管理逻辑中,这种功能被称为容器编排。
有了docker以后,运维的发布工作必须通过编排工具来实现容器的编排,如果没有编排工具,运维人员想去管理容器其实比直接管理程序要更加麻烦,增加了运维环境管理的复杂度。
常见的容器编排工具:
- machine+swarm(把N个docker主机当一个主机来管理)+compose(单机编排)
- mesos(实现统一资源调度和分配)+marathon
- kubernetes --> k8s
什么是docker
docker中的容器:
- lxc --> libcontainer --> runC
OCI&OCF
OCI
Open Container-initiative
- 由 Linux 基金会创办于 2015 年 6 月发布
- 围绕一个标准范围内和运行时制定开放的工业化标准
- 包含两个规格
- 运行时规范(runtime-spec)
- 镜像规范(image-spec)
OCF
Open Container Format
runC 是一个 CLI 工具,用于根据 OCI 规范生成和运行容器
- 容器作为 runC 的子进程启动,可以嵌入到各种其他系统中,而无需运行守护进程
- runC 建立在 libcontainer 之上,同样的容器技术支持数百万个 Docker 引擎安装
docker提供了一个服务容器的站点:https 😕/hub.docker.com
docker架构
详解:
- 镜像(Image):Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。
- 容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
- 仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。
- 客户端(client):Docker 客户端通过命令行或者其他工具来与Docker守护进程通信
- 主机(Host):一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。
- Registry:一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。
docker镜像与镜像仓库
为什么镜像仓库名字是Registry而不是repository?在docker中仓库的名字是以应用的名称取名的。
镜像是静态的,而容器是动态的,容器有其生命周期,镜像与容器的关系类似于程序与进程的关系。镜像类似于文件系统中的程序文件,而容器则类似于将一个程序运行起来的状态,也即进程。所以容器是可以删除的,容器被删除后其镜像是不会被删除的。
docker对象
当您使用 docker 时,您正在创建和使用镜像、容器、网络、卷、插件和其他对象。
- 镜像
- 镜像是一个只读模板,其中包含创建 docker 容器的说明。
- 通常,一个镜像基于另一个镜像,并带有一些额外的自定义。
- 您可以创建自己的镜像,也可以只使用其他人创建并在注册表中发布的镜像。
- 容器
- 容器是镜像的可运行实例。
- 您可以使用 docker API 或 CLI 创建、运行、停止、移动或删除容器。
- 您可以将容器连接到一个或多个网络,将存储附加到它,甚至可以根据其当前状态创建新映像。
安装及使用docker
docker安装
[root@rh1 yum.repos.d]# wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo #首先要配置一个docker-ce仓库,这里使用的是阿里云的仓库
[root@rh1 yum.repos.d]# yum install -y docker-ce --allowerasing #下载docker-ce,使用--allowerasing参数替换冲突的软件包
[root@rh1 ~]# systemctl start docker.service #运行docker
[root@rh1 ~]# docker version #查看docker版本
Client: Docker Engine - Community
Version: 20.10.17
API version: 1.41
Go version: go1.17.11
Git commit: 100c701
Built: Mon Jun 6 23:03:11 2022
OS/Arch: linux/amd64
Context: default
Experimental: true
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
docker加速
docker-ce的配置文件是/etc/docker/daemon.json,此文件默认不存在,需要我们手动创建并进行配置,而docker的加速就是通过配置此文件来实现的。
docker的加速有多种方式:
- docker cn
- 中国科技大学加速器
- 阿里云加速器(需要通过阿里云开发者平台注册帐号,免费使用个人私有的加速器)
[root@rh1 ~]# cat >/etc/docker/daemon.json << EOF ##配置docker加速
> {
> "registry-mirrors": ["https://rpnfe8c5.mirror.aliyuncs.com"]
> }
> EOF
[root@rh1 ~]# systemctl daemon-reload
[root@rh1 ~]# systemctl start docker
docker常用操作
命令 | 功能 |
---|---|
docker search | 在Docker Hub中搜索镜像 |
docker pull | 从注册表中提取映像或存储库 |
docker images | 镜像列表 |
docker create | 创建一个新的容器 |
docker start | 启动一个或多个停止的容器 |
docker run | 在新容器中运行命令 |
docker attach | 连接到运行的容器 |
docker ps | 列出本地容器 |
docker logs | 获取容器的日志 |
docker restart | 重启一个容器 |
docker stop | 停止一个或多个运行中的容器 |
docker kill | 杀死一个或多个运行中的容器 |
docker rm | 移除一个或多个容器 |
docker exec | 在运行的容器中运行命令 |
docker info | 显示整个系统的信息 |
docker inspect | 返回Docker对象的详细信息 |
示例:
[root@rh1 ~]# systemctl start docker.service
[root@rh1 ~]# docker search httpd #在Docker Hub中搜索镜像
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
httpd The Apache HTTP Server Project 4106 [OK]
centos/httpd-24-centos7 Platform for running Apache httpd 2.4 or bui… 44
centos/httpd 35 [OK]
solsson/httpd-openidc mod_auth_openidc on official httpd image, ve… 2 [OK]
clearlinux/httpd httpd HyperText Transfer Protocol (HTTP) ser… 2
[root@rh1 ~]# docker pull httpd:latest #从注册表中提取镜像 冒号后面可以选择版本
Using default tag: latest
latest: Pulling from library/httpd
a2abf6c4d29d: Pull complete
dcc4698797c8: Pull complete
41c22baa66ec: Pull complete
67283bbdd4a0: Pull complete
d982c879c57e: Pull complete
Digest: sha256:0954cc1af252d824860b2c5dc0a10720af2b7a3d3435581ca788dff8480c7b32
Status: Downloaded newer image for httpd:latest
docker.io/library/httpd:latest
[root@rh1 ~]# docker images #查看镜像列表
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd latest dabbfbe0c57b 7 months ago 144MB
[root@rh1 ~]# docker create --name web httpd #创建一个容器名为web
0ec7db7d91fa41f5f0363b52eded4c3f38b230466a485866c9437f7a3fb90004
[root@rh1 ~]# docker ps -a #查看当前所有容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
容器ID 容器使用的镜像 容器默认启动脚本 容器创建时间 容器状态 端口映射 容器名
0ec7db7d91fa httpd "httpd-foreground" 21 seconds ago Created web
[root@rh1 ~]# docker start web #启动容器
web
[root@rh1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0ec7db7d91fa httpd "httpd-foreground" 3 minutes ago Up 8 seconds 80/tcp web
[root@rh1 ~]# docker inspect web #查看容器详细信息
"Aliases": null,
"NetworkID": "248c922e84c27e3826c0eb314ba69406a37d90ba60756763d92d391a40fd29f8",
"EndpointID": "07561aae2a89db0b069683dae6e21b600cec1c28ebd9dc6dfbc62fa3b06dc687",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
[root@rh1 ~]# firewall-cmd --add-rich-rule 'rule family=ipv4 source address=0.0.0.0/0 service name=http accept' --permanent
success #配置防火墙策略
[root@rh1 ~]# firewall-cmd --reload #刷新防火墙规则
success
[root@rh1 ~]# docker run -d --name web2 -p 80:80 httpd #创建容器web2并后台启动,-d后台运行 run创建并开启 -p映射端口
6a3fd32fccc98ee23a6ededfc3acc72e4ce405e60481922b0e776958bfefdae9
[root@rh1 ~]# docker ps #
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6a3fd32fccc9 httpd "httpd-foreground" 10 seconds ago Up 8 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp web2
[root@rh1 ~]# docker rm -f $(docker ps -qa) #批量删除容器
[root@rh1 ~]# docker run -it --name web3 httpd /bin/bash #为容器设置交互式shell并进入
root@44c301d4c1c3:/usr/local/apache2#
[root@rh1 ~]# docker start web3 #启动容器web3
web3
[root@rh1 ~]# docker attach web3 #进入容器web3,退出时会自动停止容器
root@44c301d4c1c3:/usr/local/apache2#
[root@rh1 ~]# docker exec -it web2 /bin/bash #设置shell并 进入,退出时容器不会停止
[root@rh1 ~]# docker logs web2 #查看日志
[root@rh1 ~]# docker pause web2 #暂停容器
web2
[root@rh1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
44c301d4c1c3 httpd "/bin/bash" 17 minutes ago Exited (0) 13 minutes ago web3
6a3fd32fccc9 httpd "httpd-foreground" 43 minutes ago Up 43 minutes (Paused) 0.0.0.0:80->80/tcp, :::80->80/tcp web2
[root@rh1 ~]# docker unpause web2 #结束暂停
web2
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?