声明:此文章为博主个人学习记录,仅供学习和交流,如有侵权请联系博主。
Docker
基于Linux 内核的Cgroup,Namespace,以及Union FS等技术,对进程进行封装隔离,属于操作系统层面的虚拟化技术,由于隔离的进程独立于宿主和其它的隔离的进程,因此也称其为容器。
最初实现是基于LXC,从0.7 以后开始去除LXC,转而使用自行开发的Libcontainer,从1.11开始,则进一步演进为使用runC和Containerd。
Docker 在容器的基础上,进行了进一步的封装,从文件系统、网络互联到进程隔离等等,极大的简化了容器的创建和维护,使得Docker 技术比虚拟机技术更为轻便、快捷。
安装docker
基于ubuntu
基于Centos7
基于ubuntu
更新apt包索引并安装允许apt使用HTTPS仓库的软件包
$ sudo apt-get update
$ sudo apt-get install \\
ca-certificates \\
curl \\
gnupg \\
lsb-release
添加Docker的官方GPG密钥
$ sudo mkdir -m 0755 -p /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
写入阿里云镜像源地址
$ sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
更新apt包索引
sudo apt-get update
安装Docker Engine、containerd和Docker Compose
$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
基于Centos7
安装最新内核版本
#查看系统版本
cat /etc/redhat-release
#查看当前系统的内核:
uname -sr
#在 CentOS 7.x 上启用 ELRepo 仓库:
rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
rpm -Uvh https://www.elrepo.org/elrepo-release-7.0-4.el7.elrepo.noarch.rpm
#查看可用的系统内核相关包:
yum --disablerepo="*" --enablerepo="elrepo-kernel" list available
#安装最新主线内核版本:
yum -y --enablerepo=elrepo-kernel install kernel-ml
#设置默认内核版本
vi /etc/default/grub
修改GRUB_DEFAULT=0
#重新创建内核配置
grub2-mkconfig -o /boot/grub2/grub.cfg
reboot
docker环境和组件安装
#卸载旧版本docker
sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine
#gcc
yum -y install gcc
yum -y install gcc-c++
#安装yum工具包
yum -y install yum-utils
#设置阿里云的stable 镜像仓库
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
#更新 yum 软件包索引
yum makecache fast
#安装指定版本的 Docker(v20.10.8):
yum -y install docker-ce-3:20.10.8-3.el7.x86_64 docker-ce-cli-1:20.10.8-3.el7.x86_64 containerd.io
systemctl start docker
systemctl enable docker
#查看docker状态:
systemctl status docker
docker version
#镜像加速
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{
"exec-opts": ["native.cgroupdriver=systemd"],
"registry-mirrors": [
"https://du3ia00u.mirror.aliyuncs.com",
"https://hub-mirror.c.163.com",
"https://mirror.baidubce.com",
"https://registry.docker-cn.com"
],
"live-restore": true,
"log-driver":"json-file",
"log-opts": {"max-size":"500m", "max-file":"3"},
"max-concurrent-downloads": 10,
"max-concurrent-uploads": 5,
"storage-driver": "overlay2"
}
EOF
#使之生效
systemctl daemon-reload
#重启docker
systemctl restart docker
容器操作
常见命令
docker pull image:tag
docker run 启动并创建容器
--name 容器名
--rm 退出自动删除
-it 交互
-d 后台
-p 端口映射
-v 磁盘挂载
docker start container 启动容器
docker stop container 停止
docker ps -a 查看全部容器
docker exec -it image /bin/bash 进入容器
docker inspect image 查看容器信息
docker cp local:docker 拷贝文件到容器
docker images 查看镜像
Dockerfile
基本结构
FROM:指定基础镜像。
RUN:在镜像中运行命令。
CMD:指定容器启动时要运行的命令。
LABEL:为镜像添加元数据。
EXPOSE:指定容器要暴露的端口。
ENV:设置环境变量。
ADD:将文件从构建上下文或 URL 复制到镜像中。
COPY:将文件从构建上下文复制到镜像中。
ENTRYPOINT:指定容器启动时要运行的命令,可以与 CMD 配合使用。
VOLUME:创建挂载点,用于挂载外部卷。
USER:指定运行容器时要使用的用户。
WORKDIR:设置工作目录。
最佳实践
不要安装无效软件包。
应简化镜像中同时运行的进程数,理想状况下,每个镜像应该只有一个进程,当无法避免同一镜像运行多进程时,应选择合理的初始化进程(initprocess)。
最小化层级数。
最新的docker只有RUN,COPY,ADD创建新层,其他指令创建临时层,不会增加镜像大小,比如EXPOSE指令就不会生成新层。
多条RUN命令可通过连接符连接成一条指令集以减少层数。
通过多段构建减少镜像层数。
把多行参数按字母排序,可以减少可能出现的重复参数,并且提高可读性。
编写dockerfile的时候,应该把变更频率低的编译指令优先构建以便放在镜像底层以有效利用buildcache。
复制文件时,每个文件应独立复制,这确保某个文件变更时,只影响改文件对应的缓存。
Makefile文件
以go项目为示例
# 设置项目根目录
ROOT := $(shell pwd)
# 设置编译生成的可执行文件名
BINARY := myapp
# 设置编译选项
GOFLAGS := -ldflags="-s -w"
# 设置远程仓库地址
REPO := myrepo/myapp
# 设置版本号
VERSION := 1.0.0
# 默认目标
all: build
# 编译目标
build:
go build $(GOFLAGS) -o $(BINARY) main.go
# 发布目标
release: build
tar czf $(BINARY)-$(VERSION).tar.gz $(BINARY)
# 推送目标
push: release
scp $(BINARY)-$(VERSION).tar.gz $(REPO)
# 清理目标
clean:
rm -f $(BINARY)
rm -f $(BINARY)-*.tar.gz
.PHONY: all build release push clean
扩展
build构建本地镜像并上传到dockerhub
需要注册docker 账号
构建镜像 -o 指定镜像名
docker build -t imagename .
查看镜像
docker images
登录 输入账号密码
docker login
打包
docker tag tagname your_dockerhub_name/imagename
push到dockerhub仓库
docker push your_dockerhub_name/imagename
通用镜像
推荐使用这三个通用镜像:ubuntu:latest、debian:slim 和 alpine:latest
Ubuntu/Debian
Ubuntu 和 Debian 是综合能力非常强的 Linux 发行版,非常适合作为通用镜像使用,它们主要的优点如下。
- 支持的软件包众多。
- 镜像体积较小。
- 用户数量大,社区活跃,容易及时发现和修复安全问题。
- 相比较 Alpine 具有更通用的 C 语言标准库 glibc。
- 文档和教程丰富。
Alpine
我们再来看另一种通用镜像 Alpine。在很长的时间里,Alpine 发行版并没有受到太多的关注。直到 Docker 时代,大家为了追求更小的镜像体积才开始大量使用 Alpine 镜像。相比较 Debian,Alpine 有下面这些优点。
- 快速的包安装体验。
- 极小的镜像体积。
- 只包含少量的系统级程序,安全性更高。
- 更轻量的初始化系统 OpenRC。
专用镜像
各种编程语言镜像
初学使用发行版linux,尽量不要用Alpine,c库不一样
对Alpine,Dockerfile编译过程中指定 CGO_ENABLED=0
相关理论简介 (可跳过)
容器标准
•Open Container Initiative(OCI)
•轻量级开放式管理组织(项目)
•OCI主要定义两个规范
•Runtime Specification
•文件系统包如何解压至硬盘,共运行时运行。
•Image Specification
•如何通过构建系统打包,生成镜像清单(Manifest)、文件系统序列化文件、镜像配置。
Namespace
Linux Namespace是一种Linux Kernel提供的资源隔离方案:
•系统可以为进程分配不同的Namespace;
•并保证不同的Namespace资源独立分配、进程彼此隔离,即不同的Namespace下的进程互不干扰。
多种namespace互相隔离
IPC,Network,PID,Mount,UTS,USER
相关命令
查看当前系统的namespace:
lsns –t <type>
查看某进程的namespace:
ls -la /proc/<pid>/ns/
进入某namespace运行命令:
nsenter -t <pid> -n ip addr
Cgroup
•Cgroups(Control Groups)是Linux下用于对一个或一组进程进行资源控制和监控的机制。
•可以对诸如CPU使用时间、内存、磁盘I/O等进程所需的资源进行限制。
•不同资源的具体管理工作由相应的Cgroup子系统(Subsystem)来实现。
•针对不同类型的资源限制,只要将限制策略在不同的的子系统上进行关联即可。
•Cgroups在不同的系统资源管理子系统中以层级树(Hierarchy)的方式来组织管理:每个Cgroup都可以包含其他的子Cgroup,因此子Cgroup能使用的资源除了受本Cgroup配置的资源参数限制,还受到父Cgroup设置的资源限制。
文件系统 Union FS
•将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)的文件系统
•支持为每一个成员目录(类似GitBranch)设定readonly、readwrite和whiteout-able 权限
•文件系统分层, 对readonly权限的branch 可以逻辑上进行修改(增量地, 不影响readonly部分的)
•通常Union FS 有两个用途, 一方面可以将多个disk挂到同一个目录下, 另一个更常用的就是将一个readonly的branch 和一个writeable 的branch 联合在一起
docker的文件系统
典型的Linux文件系统组成:
- Bootfs(boot file system)
- Bootloader 引导加载kernel
- Kernel 当kernel被加载到内存中后umountbootfs。
rootfs(root file system)
/dev,/proc,/bin,/etc等标准目录和文件。
对于不同的linux发行版, bootfs基本是一致的,但rootfs会有差别。
docker启动过程
Linux
- 在启动后,首先将rootfs设置为readonly, 进行一系列检查, 然后将其切换为“readwrite”供用户使用。
Docker启动
初始化时也是将rootfs以readonly方式加载并检查,然而接下来利用union mount 的方式将一个readwrite文件系统挂载在readonly的rootfs之上,复用rootfs。
并且允许再次将下层的FS(file system)设定为readonly并且向上叠加。
这样一组readonly和一个writeable的结构构成一个container的运行时态, 每一个FS被称作一个FS层。
OCI容器标准
Open Container Initiative
OCI组织于2015年创建,是一个致力于定义容器镜像标准和运行时标准的开放式组织。
OCI定义了镜像标准(Runtime Specification)、运行时标准(Image Specification)和分发标准(DistributionSpecification)
- 镜像标准定义应用如何打包
- 运行时标准定义如何解压应用包并运行
- 分发标准定义如何分发容器镜像
Docker 12-Factor
12-Factor 应用是一种用于构建软件即服务(SaaS)应用的方法论。它提供了 12 个因素,用来指导开发人员如何构建可扩展、可维护和可移植的应用程序。这些因素包括:
- 代码库:应用程序应该有一个代码库,并使用版本控制系统进行管理。
- 依赖:应用程序应该显式声明并隔离其依赖关系。
- 配置:应用程序的配置应该存储在环境变量中,而不是硬编码到代码中。
- 后端服务:应用程序应该将后端服务(如数据库)视为附加资源,并通过 URL 来访问。
- 构建、发布、运行:应用程序的构建、发布和运行阶段应该严格分离。
- 进程:应用程序应该以一个或多个无状态进程的形式执行。
- 端口绑定:应用程序应该通过端口绑定来提供服务。
- 并发:应用程序应该通过进程模型来实现扩展。
- 可处理性:应用程序应该能够快速启动并优雅地关闭。
- 开发/生产环境等价性:应用程序的开发、预发布和生产环境应该尽可能相似。
- 日志:应用程序应该将日志视为事件流,并通过标准输出进行输出。
- 管理进程:应用程序的管理/运维任务应该作为一次性进程运行。