Docker与Kubernetes使用指南及最佳实践
1. Docker基础概念
1.1 镜像层与容器层
镜像层是只读层,而容器层是读写层。一个镜像可以包含多个镜像层,而每个容器只有一个容器层。当命令修改文件系统时,镜像中会创建一个新层。从同一镜像创建的两个容器,若在运行时都有写入操作,它们的数据大小通常不同。
1.2 镜像与容器的区别
形象地说,Docker镜像是产品的蓝图,而Docker容器是成品。技术上,Docker镜像包含创建一个或多个容器的指令,当容器运行时执行镜像,便会得到一个容器。此外,镜像的所有层都是只读的,而运行镜像创建容器时,会在容器上创建一个顶层可写层。
2. Docker主要技术
2.1 Docker Desktop
Docker Desktop是一个简化的图形用户界面(GUI),用于使用Docker构建容器化应用程序。其最大优势是提供易于访问的用户界面,可在本地系统上管理所有应用程序及其容器。通过鼠标点击即可完成许多配置和设置,让开发者和团队更专注于应用程序代码。安装Docker Desktop可访问所有关键的Docker技术,包括:
- Docker Engine
- Docker CLI客户端
- Docker Compose
- Docker Content Trust
此外,安装Docker Desktop还会提供最新版本的Kubernetes和原生Windows Hyper-V虚拟机。
2.2 Docker扩展
Docker扩展通过允许使用第三方工具来扩展Docker Desktop的功能,可使用的第三方工具数量没有限制。
2.3 Docker引擎
Docker引擎用于构建容器化应用程序,采用客户端 - 服务器架构。其中,
dockerd
作为Docker服务器,
docker CLI
作为Docker客户端,客户端通过API调用与服务器交互。Docker引擎还提供了Docker容器的存储和网络功能。
2.4 容器网络相关
- 默认IP地址 :容器创建时会获得一个IP地址。
- 对外暴露 :默认情况下,容器不会暴露给外部服务,需要进行显式配置才能实现对外访问。
-
网络连接
:可以使用
--network标志将容器连接到单个网络,也可以使用docker network connect命令将容器连接到多个网络。
2.5 Docker构建
Docker Build用于打包代码和构建Docker镜像,还可用于:
- 执行多阶段构建
- 创建可在多个平台和架构上运行的镜像
- 缓存构建过程
- 配置构建驱动程序
- 编排多个并行构建
2.6 Docker Compose
Docker Compose是一个Docker应用程序,允许定义和运行包含多个容器的应用程序。例如,对于包含前端、后端和内存数据库三个服务的应用程序,可使用Docker Compose创建一个文件,将这三个服务作为不同的容器运行,而无需分别启动。它可用于管理所有应用环境(开发、系统集成测试、用户验收测试和生产)中应用程序的端到端生命周期。
3. 主要Docker命令
3.1 通用命令
| 命令 | 描述 |
|---|---|
docker -d
| 启动Docker守护进程 |
docker info
| 显示Docker的一般信息和版本信息 |
docker –help
| 查看Docker命令的帮助信息 |
docker login -u <<<USERNAME>>>
| 使用用户名登录Docker Hub账户 |
docker logout
| 从Docker Hub账户注销 |
3.2 镜像相关命令
| 命令 | 描述 |
|---|---|
docker build
| 使用当前目录中的Dockerfile构建镜像 |
docker build -f <<<DOCKER_FILENAME>>>
| 使用指定的Dockerfile名称构建镜像 |
docker build -t <<<DOCKER_IMAGE_NAME>>>
| 构建镜像并为其添加标签 |
docker build --no-cache
| 不使用缓存构建镜像 |
docker images
| 列出所有Docker镜像 |
docker rmi <<<DOCKER_IMAGE_NAME>>>
或
docker image rm <<<DOCKER_IMAGE_NAME>>>
| 删除Docker镜像 |
docker pull <<<DOCKER_IMAGE_NAME>>>
| 从Docker注册表中拉取镜像 |
docker push <<<DOCKER_IMAGE_NAME>>>
| 将镜像推送到Docker注册表 |
docker search <<<DOCKER_IMAGE_NAME>>>
| 在Docker注册表中搜索镜像 |
docker inspect <<<IMAGE_ID>>>
| 检查镜像信息 |
docker image inspect --format='{{json .RootFS.Layers}}' <<<IMAGE_ID>>>
| 显示镜像的所有层 |
3.3 容器相关命令
| 命令 | 描述 |
|---|---|
docker ps
| 列出所有运行中的容器 |
docker ps --all
| 列出所有运行和停止的容器 |
docker run <<<DOCKER_IMAGE_NAME>>>
| 将Docker镜像作为容器运行 |
docker run --name <<<CONTAINER_NAME>>> <<<DOCKER_IMAGE_NAME>>>
| 将Docker镜像作为容器运行,并指定容器名称 |
docker run -d <<<DOCKER_IMAGE_NAME>>>
| 在后台将Docker镜像作为容器运行 |
docker run -p <<<HOST_PORT>>>:<<<CONTAINER_PORT>>> <<<DOCKER_IMAGE_NAME>>>
| 将容器的端口发布到主机 |
docker start <<<CONTAINER_NAME_OR_ID>>>
| 启动停止的容器 |
docker stop <<<CONTAINER_NAME_OR_ID>>>
| 停止运行的容器 |
docker restart <<<CONTAINER_NAME_OR_ID>>>
| 重启运行的容器 |
docker rm <<<CONTAINER_NAME_OR_ID>>>
| 删除容器 |
docker exec -it <<<CONTAINER_NAME_OR_ID>>> <<<COMMAND>>>
| 在运行的容器内交互式执行命令 |
docker logs -f <<<CONTAINER_NAME_OR_ID>>>
| 显示运行或停止的容器的日志 |
docker container stats
| 显示运行容器的使用统计信息 |
4. Docker最佳实践
4.1 Docker开发最佳实践
4.1.1 尽量减小镜像大小
大镜像会增加构建时间和容器部署时间,可通过以下方法减小镜像大小:
- 避免从头开始构建镜像,选择Docker官方镜像仓库中已有的基础镜像。
- 使用多阶段构建,例如先使用基础镜像构建应用程序,然后切换到容器运行时镜像,因为运行时不需要构建时拉取的库。
- 如果有多个镜像且它们之间有很多公共组件,可尝试构建自己的基础镜像,公共层只需加载一次并会被缓存。
- 为镜像添加有用的元数据,如发布版本号、环境详细信息等。
- 为调试和故障排除目的创建单独的镜像,并基于生产镜像构建调试镜像,以保持生产镜像的精简。
- 使用
.dockerignore
文件排除最终镜像中不必要的文件和目录。
4.1.2 高效管理数据
容器的运行时数据不应存储在容器的可写层,这不仅会增加容器大小,还会降低I/O效率。建议使用卷和绑定挂载来存储数据。对于机密数据,可使用Secrets;对于非机密配置数据,可使用Configs。
4.1.3 利用CI/CD管道
强烈建议在所有非生产和生产部署中使用CI/CD管道,不仅可以自动化应用程序的部署,还能从审计角度进行跟踪。在生产部署前,可使用
docker trust
命令对镜像进行签名,镜像必须经过开发、测试、质量和安全团队的签名才能部署到生产环境。
4.2 Dockerfile最佳实践
4.2.1 FROM指令
尽量使用官方基础镜像以创建精简镜像,例如如果需要基于Linux的基础镜像,可考虑使用Alpine镜像,其体积小,适合作为基础镜像。
4.2.2 LABEL指令
使用
LABEL
指令为镜像添加元数据。
4.2.3 RUN指令
为提高可读性,可使用反斜杠(
\
)将长的
RUN
命令拆分为多行,例如:
RUN apt-get update && apt-get install -y \
default-jdk \
default-jre \
4.2.4 CMD指令
推荐使用以下格式指定
CMD
指令:
CMD ["exe", "argument1", "argument2"]
4.2.5 EXPOSE指令
在
EXPOSE
指令中使用常用的端口号,例如对于Web服务器镜像,使用端口80处理HTTP流量,端口443处理HTTPS流量。
4.2.6 ENV指令
使用
ENV
指令修改
PATH
环境变量,也可用于定义常用的版本号,但要注意该指令会创建一个新的中间镜像层。
4.2.7 COPY指令
尽量逐个复制文件,而不是使用单个
COPY
指令复制所有文件,这样可以减少缓存失效的次数。
4.2.8 ADD指令
不要使用
ADD
指令从远程仓库拉取库或文件,建议使用
wget
和
curl
等命令。
4.2.9 VOLUME指令
使用
VOLUME
指令暴露容器创建的存储。
4.2.10 WORKDIR指令
为提高可读性,在
WORKDIR
指令中使用绝对路径。
4.3 Docker安全最佳实践
4.3.1 保持镜像大小小
尽量减小镜像大小,因为镜像越小,攻击面越小。大镜像依赖项多,每个依赖项都可能存在漏洞。
4.3.2 选择经过验证的基础镜像
从头创建镜像时,使用镜像仓库中官方或经过验证的基础镜像。可在Docker Hub上查找 “Official Image” 和 “Verified Publisher” 徽章来识别官方和经过验证的镜像,选择精简的基础镜像也有助于减小整体镜像大小。
4.3.3 优先使用多阶段构建
使用多阶段构建消除前一层中不必要的依赖项、库和工件,有助于减小镜像大小。
4.3.4 定期重建镜像
建议定期使用
--no-cache
子句重建镜像,使缓存失效并允许进行全新下载。
5. Kubernetes最佳实践
5.1 Kubernetes开发最佳实践
5.1.1 规范文件格式
可使用JSON和YAML两种格式创建规范文件,虽然技术上两种格式都可行,但YAML格式更常用。
5.1.2 分组相关对象定义
尝试将相关对象的定义分组在一个规范文件中,便于管理大型应用程序中的对象定义。可在文件中使用
---
分隔多个对象的定义,例如:
apiVersion: v1
kind: Pod
metadata:
name: ha-nginx-pod-init-1
spec:
containers:
- name: ha-nginx-c-1
image: nginx:1.10.1
ports:
- containerPort: 80
---
apiVersion: v1
kind: Pod
metadata:
name: ha-nginx-pod-init-2
spec:
containers:
- name: ha-nginx-c-1
image: nginx:1.10.1
ports:
- containerPort: 80
5.1.3 存储规范文件
除Secret对象外,将所有规范文件存储在代码仓库中,对规范文件进行版本控制,以便查看对象的历史更改。
5.1.4 使用最新API版本
在规范文件的
apiVersion
字段中始终使用最新的API版本值。
5.1.5 遵循命名约定
为规范文件遵循命名约定,例如包含前端部署服务对象定义的规范文件可命名为
frontend-service-deployment.yaml
。
5.1.6 避免硬编码默认值
不要硬编码默认值,以免未来默认值调整时无法受益。
5.1.7 分配有意义的标签
为对象分配有意义的标签,特别是Kubernetes推荐的标签,有助于基于条件选择和过滤对象。
5.1.8 使用注解
使用注解为对象添加元数据。
5.1.9 管理Pod
默认情况下,Pod不会自动重启,可使用ReplicaSets或Deployment对象管理Pod,Deployment对象会隐式创建ReplicaSet。
5.1.10 创建服务
创建服务以暴露部署时,先创建服务对象,再创建部署对象。这样,部署创建时所有容器将自动获取与服务相关的环境变量。
5.1.11 使用无头服务
当不需要
kube-proxy
提供的负载均衡时,可使用无头服务。
5.2 大型集群最佳实践
5.2.1 使用资源配额和限制范围
使用资源配额和限制范围,确保没有特定的命名空间或对象占用所有集群资源。
5.2.2 确保主节点性能
主节点(或控制平面)是集群的关键组件,因为所有集群管理都在主节点上进行,所以要确保主节点有足够的计算能力,以保证集群性能良好。
5.2.3 保证集群容错性
每个故障区域至少应有一个主节点,即使是中小型集群,这也是重要的考虑因素。
5.2.4 足够的etcd存储
由于所有集群状态都存储在
etcd
存储中,因此要确保
etcd
存储足够大。
5.2.5 单独的etcd实例存储事件
由于事件对象可能很大,可考虑使用单独的
etcd
实例存储事件,并显式配置
kube-apiserver
引用该实例获取事件信息。
5.3 通用安全最佳实践
5.3.1 监控容器事件
监控所有关键容器事件,以检测表明存在漏洞或意外活动的事件,通过正确分析事件还可检测容器配置错误。
5.3.2 确保镜像安全
容器是镜像的运行时实例,要确保容器安全,镜像必须安全。可通过建立镜像构建策略、仅使用官方或经过验证的基础镜像以及尽量减小镜像大小等方法创建安全的镜像。
5.3.3 定期测试和分析基础镜像
定期测试和分析基础镜像,以识别任何安全风险或漏洞。
5.3.4 确保容器安全
如果黑客访问了容器,与受影响容器可通信的所有容器和Pod都将受到威胁,因此要尽力确保容器的安全。
5.3.5 定义和实施Pod网络策略
定义并实施Pod网络策略,以防止意外的Pod间通信,因为默认情况下所有Pod都可以相互通信。
5.3.6 创建命名空间
创建命名空间,根据功能、业务优先级或其他指标分隔工作负载,这有助于限制攻击的影响,对集群安全和管理都有益。
5.3.7 监控集群网络流量
监控集群网络流量,识别违反网络策略的流量。
通过遵循这些Docker和Kubernetes的最佳实践,可以提高应用程序的开发效率、安全性和性能,确保容器化应用程序在各种环境中稳定运行。
6. 总结与实践建议
6.1 关键要点回顾
为了更清晰地回顾Docker与Kubernetes的关键知识点,我们通过以下表格进行总结:
| 技术领域 | 关键要点 |
| — | — |
| Docker基础概念 | 镜像层只读,容器层读写;镜像与容器的区别,如镜像为蓝图,容器为成品 |
| Docker主要技术 | Docker Desktop提供GUI管理;Docker Engine用于构建应用;Docker Compose管理多容器应用等 |
| 主要Docker命令 | 涵盖通用、镜像相关、容器相关等多种命令,用于不同操作场景 |
| Docker最佳实践 | 开发上减小镜像大小、高效管理数据、利用CI/CD;Dockerfile遵循各指令最佳写法;安全上保持镜像小、选验证镜像等 |
| Kubernetes最佳实践 | 开发上规范文件格式、分组对象定义等;大型集群确保资源合理使用、主节点性能等;安全上监控事件、确保镜像安全等 |
6.2 实践流程建议
在实际项目中,可以按照以下mermaid流程图所示的流程来运用Docker和Kubernetes:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px
A([项目启动]):::startend --> B{选择基础镜像}:::decision
B -->|官方或验证镜像| C(编写Dockerfile):::process
C --> D(构建Docker镜像):::process
D --> E(使用Docker Compose定义多容器应用):::process
E --> F(使用CI/CD管道部署):::process
F --> G(创建Kubernetes规范文件):::process
G --> H(部署到Kubernetes集群):::process
H --> I(监控与维护):::process
I --> J{是否需要调整}:::decision
J -->|是| C
J -->|否| K([项目完成]):::startend
6.3 操作步骤总结
6.3.1 Docker操作步骤
- 选择基础镜像 :从Docker官方镜像仓库挑选合适的基础镜像。
- 编写Dockerfile :按照Dockerfile最佳实践,使用各指令编写文件。
-
构建镜像
:使用
docker build相关命令构建镜像。 -
管理容器
:使用容器相关命令,如
docker run运行容器,docker stop停止容器等。 -
使用Docker Compose
:编写
docker-compose.yml文件定义多容器应用,使用docker-compose up启动应用。 -
利用CI/CD管道
:配置CI/CD工具,使用
docker trust签名镜像后部署。
6.3.2 Kubernetes操作步骤
- 创建规范文件 :使用YAML格式创建Kubernetes规范文件,遵循开发最佳实践。
-
分组对象定义
:在文件中使用
---分隔相关对象定义。 - 存储规范文件 :将规范文件存储在代码仓库进行版本控制。
-
部署到集群
:使用
kubectl apply -f命令将规范文件部署到Kubernetes集群。 -
监控与维护
:使用
kubectl相关命令监控集群状态,如kubectl get pods查看Pod状态。 - 安全管理 :实施安全最佳实践,如监控容器事件、定义网络策略等。
通过以上总结和实践建议,希望能帮助大家更系统地掌握Docker和Kubernetes的使用方法和最佳实践,在实际项目中更好地运用这些技术,提升应用的开发和部署效率,保障系统的安全性和稳定性。
超级会员免费看
775

被折叠的 条评论
为什么被折叠?



