制作容器镜像的最佳实践

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 制作容器镜像的最佳实践

概述

这篇文章主要是我日常工作中的制作镜像的实践, 同时结合我学习到的关于镜像制作的相关文章总结出来的. 包括通用的容器最佳实践, java, nginx, python 容器最佳实践. 最佳实践的目的一方面保证镜像是可复用的, 提升 DevOps 效率, 另一方面是为了提高安全性. 希望对各位有所帮助.

本文分为四部分内容, 分别是:

  1. 通用容器镜像最佳实践
  2. Java 容器镜像最佳实践
  3. NGINX 容器镜像最佳实践
  4. 以及 Python 容器最佳实践

通用容器镜像最佳实践

使用 LABEL maintainer

LABEL maintainer 指令设置镜像的作者姓名和邮箱字段。示例如下:

LABEL maintainer="cuikaidong@foxmail.com"
DOCKERFILE

复用镜像

建议尽量使用 FROM 语句复用合适的上游镜像。这可确保镜像在更新时可以轻松从上游镜像中获取安全补丁,而不必直接更新依赖项。

此外,在 FROM 指令中使用标签 tag(例如 alpine:3.13),使用户能够清楚地了解镜像所基于的上游镜像版本。

禁止 使用 latest tag 以确保镜像不会受到 latest 上游镜像版本的重大更改的影响。

保持标签 TAGS 的兼容性

给自己的镜像打标签时,注意保持向后兼容性。例如,如果制作了一个名为example 的镜像,并且它当前为 1.0 版,那么可以提供一个 example:1 标签。后续要更新镜像时,只要它继续与原始镜像兼容,就可以继续标记新镜像为 example:1,并且该 tag 的下游消费者将能够在不中断的情况下获得更新。

如果后续发布了不兼容的更新,那么应该切换到一个新 tag,例如 example:2。那么下游消费者可以按照自身实际情况升级到新版本,而不会因为新的不兼容镜像而造成事故。但是任何使用 example:latest的下游消费者都会承担引入不兼容更改的风险, 所以这也是前面我强烈建议不要使用 latest tag 的原因.

避免多个进程

建议 不要 在一个容器内启动多个服务,例如 nginx 和 后端 app。因为容器是轻量级的,可以很容易地通过 Docker Compose 或 Kubernetes 链接在一起。Kubernetes 或基于此的 TKE 容器平台通过将相关镜像调度到单个 pod 中,轻松地对它们进行集中管理。

在封装脚本中使用 EXEC 指令

许多镜像会通过在启动应用程序之前使用封装脚本进行一些设置。如果您的镜像使用这样的脚本,那么该脚本最后应该使用 exec 启动应用程序,以便用应用程序的进程替换该脚本的进程。如果不使用 exec,那么容器运行时发送的信号(比如 TERMSIGKILL)将转到封装脚本,而不是应用程序的进程。这不是我们所期望的。

清除临时文件

应删除在生成过程中创建的 所有临时文件 。这还包括使用 ADD 指令添加的任何文件。例如,👍 我们强烈建议您在执行apt-get install 操作之后运行 rm -rf /var/lib/apt/lists/* 命令。

通过如下创建 RUN 语句,可以防止 apt-get 缓存存储在镜像层中:

RUN apt-get update && apt-get install -y \
    curl \
    s3cmd=1.1.* \
 && rm -rf /var/lib/apt/lists/*
DOCKERFILE

请注意,如果您改为:

RUN apt-get install curl -y
RUN apt-get install s3cmd -y && rm -rf /var/lib/apt/lists/*
DOCKERFILE

那么,第一个 apt-get 调用会在这一层 (image layer) 中留下额外的文件,并且在稍后运行rm -rf ... 操作时,无法删除这些文件。额外的文件在最终镜像中不可见,但它们会占用空间。

另外,在一条 RUN 语句中执行多个命令可以减少镜像中的层数,从而缩短下载和安装时间。

yum 的例子如下:

RUN yum -y install curl && yum -y install s3cmd && yum clean all -y
DOCKERFILE

📓 备注:

  1. RUNCOPYADD 步骤会创建镜像层。
  2. 每个层包含与前一层的差异项。
  3. 镜像层会增加最终镜像的大小。

📓 提示:

  1. 将相关命令(apt-get install)放入同一 RUN 步骤。
  2. 在同一 RUN 步骤中删除创建的文件。
  3. 避免使用 apt-get upgradeyum upgrade all ,因为它会把所有包升级到最新版本.

按正确的顺序放置指令

容器构建过程中, 读取 dockerfile 并从上到下运行指令。成功执行的每一条指令都会创建一个层,在下次构建此镜像或另一个镜像时可以重用该层。建议在 Dockerfile 的顶部放置很少更改的指令。这样做可以确保同一镜像的下一次构建速度非常快,因为上层更改的缓存还在, 可以复用。

例如,如果正在处理一个 dockerfile,其中包含一个用于安装正在迭代的文件的 ADD 指令,以及一个用于 apt-get install 包的 RUN 指令,那么最好将 ADD 命令放在最后:

FROM alpine:3.11
RUN apt-get -y install curl && rm -rf /var/lib/apt/lists/*
ADD app /app
DOCKERFILE

这样,每次编辑 app 并重新运行 docker build 时,系统都会为 apt-get 命令复用缓存层,并且只为 ADD 操作生成新层。

如果反过来, dockerfile 如下:

FROM alpine:3.11
ADD app /app
RUN apt-get -y install curl && rm -rf /var/lib/apt/lists/*
DOCKERFILE

那么,每次更改 app 然后再次运行 docker build 时,ADD 操作都会使镜像层的缓存失效,因此必须重新运行 apt-get 操作。

标记重要端口

EXPOSE 指令使容器中的端口对主机系统和其他容器可用。虽然可以指定使用 docker run -p 调用公开端口,但在dockerfile 中使用 EXPOSE 指令可以通过显式声明应用程序需要运行的端口,使人和应用程序更容易使用您的镜像:

  • 暴露的端口将显示在 docker ps 下。
  • docker inspect 返回的镜像的元数据中也会显示暴露的端口。
  • 当将一个容器链接到另一个容器时,会链接暴露的端口。

设置环境变量

👍️ 使用 ENV 指令设置环境变量是很好的实践。一个例子是设置项目的版本。这使得人们在不查看 dockerfile 的情况下很容易找到版本。另一个例子是在公布一条可以被另一个进程使用的路径,比如 JAVA_HOME.

避免默认密码

最好 避免设置默认密码 。许多人会扩展基础镜像,但是忘记删除或更改默认密码。如果为生产中的用户分配了一个众所周知的密码,这可能会导致安全问题。👍️ 应该使用环境变量, secret 或其他 K8s 加密方案来配置密码

如果确实选择设置默认密码,请确保在容器启动时显示适当的警告消息。消息应该通知用户默认密码的值,并说明如何更改,例如设置什么环境变量。

禁用 SSHD

禁止在镜像中运行 sshd。可以使用 docker exec 命令访问本地主机上运行的容器。或者,可以使用 kubectl exec 命令来访问在 K8s 或 TKE 容器平台上运行的容器。在镜像中安装和运行 sshd 会遭受潜在攻击, 需要额外的安全补丁修复。

将 VOLUMES(卷) 用于持久数据

镜像应使用 来存储持久数据。这样,Kubernetes 或 TKE 将网络存储挂载到运行容器的节点,如果容器移动到新节点,则存储将重新连接到该节点。通过将卷用于所有持久化存储的需求,即使重新启动或移动容器,也会保留持久化内容。如果镜像将数据写入容器内的任意位置,则可能数据会丢失。

此外,在 Dockerfile 中显式定义卷使镜像的消费者很容易理解在运行镜像时必须定义哪些卷。

有关如何在 K8s 或 TKE 容器平台中使用卷的更多信息,请参阅 Kubernetes documentation.

使用非 root 用户运行容器进程

默认情况下,Docker 用容器内部的 root 运行容器进程。这是一个不安全的做法,因为如果攻击者设法突破容器,他们可以获得对 Docker 宿主机的 root 权限。

注意:

如果容器中是 root,那么逃逸出来就是主机上的 root。

使用多阶段构建

利用 多阶段构建 来创建一个用于构建工件的临时镜像,该工件将被复制到生产镜像上。临时构建镜像将与与该映像关联的原始文件、文件夹和依赖项一起丢弃。

这会产生了一个精益,生产就绪的镜像。

一个用例是使用非 Alpine 基础镜像来安装需要编译的依赖项。然后可以将 wheel 文件复制到最终镜像。

Python 示例如下:

FROM python:3.6 as base
COPY requirements.txt /
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /wheels -r requirements.txt
FROM python:3.6-alpine
COPY --from=base /wheels /wheels
COPY --from=base requirements.txt .
RUN pip install --no-cache /wheels/* # flask, gunicorn, pycrypto
WORKDIR /app
COPY . /app
DOCKERFILE

使用前大小: 705MB, 使用后大小: 103MB

禁止在容器中存储机密信息

禁止在容器中存储机密信息, 包括:

  • 敏感信息
  • 数据库凭据
  • ssh 密钥
  • 用户名和密码
  • api 令牌等

以上信息可以通过:

  • 环境变量 ENV 传递
  • 卷 VOLUME 挂载

避免将文件放入 /tmp

对于一些应用程序(如: python 的 gunicorn), 会将某些缓存信息或心跳检测信息写入 /tmp 中, 这对 /tmp 的读写性能有较高要求, 如果 /tmp 挂载的是普通磁盘, 可能导致严重的性能问题.

在某些 Linux 发行版中,/tmp 通过 tmpfs 文件系统存储在内存中。但是,Docker 容器默认情况下没有为 /tmp 打开 tmpfs

$ docker run --rm -it ubuntu:18.04 df
Filesystem       1K-blocks     Used Available Use% Mounted on
overlay           31263648 25656756   3995732  87% /
tmpfs                65536        0     65536   0% /dev
tmpfs              4026608        0   4026608   0% /sys/fs/cgroup
/dev/mapper/root  31263648 25656756   3995732  87% /etc/hosts
shm                  65536        0     65536   0% /dev/shm
BASH

如上所示,/tmp 正在使用标准的 Docker overlay 文件系统:它由普通的块设备或计算机正在使用的硬盘驱动器支持。这可能导致性能问题 .

针对这类应用程序, 通用的解决方案是将其临时文件存储在其他地方。特别是,如果你看上面你会看到 /dev/shm 使用 shm 文件系统共享内存和内存文件系统。所以你需要做的就是使用 /dev/shm 而不是 /tmp

使用 Alpine Linux 基础镜像 (谨慎采纳)

使用基于Alpine Linux 的镜像,因为它只提供必要的包, 生成的镜像更小。

收益有:

  1. 减少了主机成本,因为使用的磁盘空间更少
  2. 更快的构建、下载和运行时间
  3. 更安全(因为包和库更少)
  4. 更快的部署

示例如下:

FROM python:3.6-alpine
WORKDIR /app
COPY requirements.txt /
RUN pip install -r /requirements.txt  # flask and gunicorn
COPY . /app
DOCKERFILE

使用前大小: 702MB, 使用后大小: 102MB

注意:

谨慎使用 alpine, 我看到过使用 Alpine Linux 产生的一大堆问题,因为它建立在 musl libc 之上,而不是大多数 Linux 发行版使用的 GNU libc(glibc)。问题有: 日期时间格式的错误, 由于堆栈较小导致的崩溃等等。

使用 .dockerignore 排除无关文件

要排除与构建无关的文件,请使用 .dockerignore 文件。此文件支持与 .gitignore 文件类似的排除模式。具体请参阅 .dockerignore 文件

不要安装不必要的包

为了降低复杂性,依赖性,文件大小和构建时间,请避免安装额外的或不必要的应用程序包。例如,不需要在数据库镜像中包含文本编辑器。

解耦应用程序

每个容器应该只有一个进程。将应用程序分离到多个容器中可以更容易地水平扩展和重用容器。例如,Web 应用程序堆栈 LNMP 可能包含三个独立的容器,每个容器都有自己独特的映像,以分离的方式管理 Web 服务器, 应用程序,缓存数据库和数据库。

将每个容器限制为一个进程是一个很好的经验法则,但它不是一个硬性规则。例如,可以 使用 init 进程生成 容器 ,另外某些程序可能会自行生成其他子进程 (如: nginx)。

根据自己的经验进行判断,尽可能保持容器简洁和模块化。如果容器彼此依赖,则可以使用 容器网络 或 K8s Sidecar 来确保这些容器可以进行通信。

对多行参数进行排序

建议通过按字母顺序排序多行参数来方便后续的更改。这有助于避免重复包并使列表更容易更新。这也使 PR 更容易阅读和审查。在反斜杠(\)之前添加空格也有帮助。

下面是来自一个示例 openjdk 图像

...
  apt-get update; \
  apt-get install -y --no-install-recommends \
    dirmngr \
    gnupg \
    wget \
  ; \
  rm -rf /var/lib/apt/lists/*; \
...
DOCKERFILE

JAVA 容器镜像最佳实践

IDE 插件推荐

  • idea - 转到“首选项”、“插件”、“安装 JetBrains 插件…”,搜索“Docker”并单击“安装”
  • Eclipse

📓 备注:

Docker and IntelliJ IDEA

Docker and Eclipse

设置内存限制相关参数

📓 备注:

指定 -Xmx=1g 将告诉 JVM 分配一个 1 GB 堆, 但是它并没有告诉 JVM 将其整个内存使用量限制为 1 GB。除了对内存, 还会有 card tables、code cache 和各种其他堆外数据结构。用于指定总内存使用量的参数是 -XX:MaxRAM。请注意,使用 -XX:MaxRam=500m 时,堆将大约为 250 MB。

JVM 在历史上查找 /proc 以确定有多少可用内存,然后根据该值设置其堆大小。不幸的是,像 docker 这样的容器在 /proc 中不提供特定于容器的信息。2017 年之后有一个补丁,提供了一个 -XX:+UseCGroupMemoryLimitForHeap命令行参数,它告诉 jvm 查找 /sys/fs/cgroup/memory/memory.limit_in_bytes,以确定有多少可用内存。如果这个补丁在运行的 OpenJDK 版本中不可用,可以通过显式设置 -XX:MaxRAM=n 来代替。

总结, 设置内存限制相关参数:

  1. Openjdk 8 的新版本, 添加: -XX:+UseCGroupMemoryLimitForHeap
  2. 如果没有上边的参数, 设置:-XX:MaxRAM=n
  3. 建议设置 JVM Heap 约为 memory limit 的 50% - 80%
  4. 建议设置 JVM MaxRAM 接近 K8s pod 的 memory limit

设置 GC 策略

OpenJDK8 中有一个补丁,它将使用 cgroup 可用的信息来计算适当数量的并行 GC 线程。但是,如果这个补丁在您用的 OpenJDK 版本中不可用,假设您的容器宿主机有 8 个 CPU, 但是容器中 CPU limit 为 2 个 CPU, 那么您最终可能会得到 8 个并行 GC 线程。解决方法是显式指定并行 GC 线程的数量: -XX:ParallelGCThreads=2

如果您的容器中 cpu limit 设置为只有一个 CPU,强烈建议使用 -XX:+UseSerialGC 运行,来完全避免并行 GC。

JAVA 启动阶段调优

JAVA 程序都有一个启动阶段,它需要大量的堆,之后可能会进入一个安静的循环阶段,在这个阶段它就不需要太多的堆。

对于串行 GC 策略, 您可以通过配置使它更具侵略性, 如: -XX:MinHeapFreeRatio=20(当堆占用率大于 80%,此值默认增大。)

XX:MaxHeapFreeRatio=40(堆占用率小于 60% 时收缩)

对于并行 - parallel GC 策略, 推荐如下配置:

-XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90

JAVA 容器全局建议资源请求和资源限制

JAVA 程序都有一个启动阶段,启动阶段也会大量消耗 CPU, CPU 使用越多, 启动阶段越短.

下面是一个表,总结了不同 CPU 限制下的 spring boot 示例应用启动时间(CPU 以 millicore 为单位):

  • 500m - 80 seconds
  • 1000m - 35 seconds
  • 1500m - 22 seconds
  • 2500m - 17 seconds
  • 3000m - 12 seconds

根据以上情况, K8s 或 TKE 容器平台管理员可以考虑对 JAVA 容器做如下限制:

  • 使用 CPU requests, 不设置 cpu limit
  • 使用 memory limit 且等于 memory request

示例如下:

resources:
  requests:
    memory: "1024Mi"
    cpu: "500m"
  limits:
    memory: "1024Mi"
YAML

使用 ExitOnOutOfMemoryError 而非 HeapDumpOnOutOfMemoryError (谨慎评估)

我们都知道, 在传统的虚拟机上部署的 Java 实例. 为了更好地分析问题, 一般都是要加上: -XX:+HeapDumpOnOutOfMemoryError这个参数的, 加这个参数后, 如果遇到内存溢出, 就会自动生成 HeapDump , 后面我们可以拿到这个 HeapDump 来更精确地分析问题.

但是, 容器技术的应用, 带来了一些不同, 在使用容器平台后, 我们更倾向于:

  1. 遇到故障快速失败
  2. 遇到故障快速恢复
  3. 尽量做到用户对故障 " 无感知 "

所以, 针对 Java 应用容器, 我们也要优化以满足这种需求, 以 OutOfMemoryError 故障为例:

  1. 遇到故障快速失败, 即尽可能 " 快速退出, 快速终结 "

-XX:+ExitOnOutOfMemoryError 就正好满足这种需求:

传递此参数时,抛出 OutOfMemoryError 时 JVM 将立即退出。 如果您想尽快终止异常应用程序,则可以传递此参数。

NGINX 容器镜像最佳实践

如果您直接在基础硬件或虚拟机上运行 NGINX,通常需要一个 NGINX 实例来使用所有可用的 CPU。由于 NGINX 是多进程模式,通常你会启动多个 worker processes,每个工作进程都是不同的进程,以便利用所有 CPU。

但是,在容器中运行时,如果将 worker_processes 设置为 auto, 会根据容器所在宿主机的 CPU 核数启动相应进程数. 比如, 我之前在物理机上运行 NGINX 容器使用 auto 参数, 尽管 CPU limit 设置为 2, 但是 NGINX 会启动 64 (物理机 CPU 数) 个进程.

因此,👍️建议根据 实际需求或 CPU limit 的设置配置 nginx.conf, 如下:

worker_processes  2;
NGINX

Python 容器镜像最佳实践

🐾Warning:

随着时间的迁移, 以及实践的深入, 最佳实践也在发生着变化, 以下部分内容已经不能作为 Python 容器镜像的最佳实践.

最新的 Python 容器镜像最佳实践可以参见这篇文章: https://EWhisper.cn/posts/25776/

示例如下:

# 基于官方基础镜像
FROM python:3.7-alpine
# 设置工作目录
WORKDIR /app
# 设置环境变量
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV DEBUG 0
# install psycopg2
RUN apk update \
    && apk add --virtual build-deps gcc musl-dev python3-dev \
    && apk add postgresql-dev \
    && pip install psycopg2 \
    && apk del build-deps
# install dependencies
COPY ./requirements.txt .
RUN pip install -r requirements.txt
# copy project
COPY . .
# 切换到非 root 用户
RUN adduser -D myuser
USER myuser
# run gunicorn
CMD gunicorn hello_django.wsgi:application --bind 0.0.0.0:$PORT
DOCKERFILE

△ 示例 Dockerfile

IDE 插件推荐

  • PyCharm - 同 Idea
  • VSCode -Visual Studio Code Remote - Containers插件

建议配置的环境变量

# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
ENV DEBUG 0
DOCKERFILE
  1. PYTHONDONTWRITEBYTECODE: 防止 python 将 pyc 文件写入硬盘
  2. PYTHONUNBUFFERED: 防止 python 缓冲 stdout 和 stderr
  3. DEBUG: 方便根据环境类型的不同 (测试 / 生产) 调整是否开启 debug

安装数据库驱动包的方法

以 postgredb 的驱动 psycopg2 为例, 可能需要安装额外的基础组件:

# install psycopg2
RUN apk update \
    && apk add --virtual build-deps gcc musl-dev python3-dev \
    && apk add postgresql-dev \
    && pip install psycopg2 \
    && apk del build-deps
相关实践学习
通过容器镜像仓库与容器服务快速部署spring-hello应用
本教程主要讲述如何将本地Java代码程序上传并在云端以容器化的构建、传输和运行。
Kubernetes极速入门
Kubernetes(K8S)是Google在2014年发布的一个开源项目,用于自动化容器化应用程序的部署、扩展和管理。Kubernetes通常结合docker容器工作,并且整合多个运行着docker容器的主机集群。 本课程从Kubernetes的简介、功能、架构,集群的概念、工具及部署等各个方面进行了详细的讲解及展示,通过对本课程的学习,可以对Kubernetes有一个较为全面的认识,并初步掌握Kubernetes相关的安装部署及使用技巧。本课程由黑马程序员提供。   相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
23天前
|
Kubernetes 监控 开发者
掌握容器化:Docker与Kubernetes的最佳实践
【10月更文挑战第26天】本文深入探讨了Docker和Kubernetes的最佳实践,涵盖Dockerfile优化、数据卷管理、网络配置、Pod设计、服务发现与负载均衡、声明式更新等内容。同时介绍了容器化现有应用、自动化部署、监控与日志等开发技巧,以及Docker Compose和Helm等实用工具。旨在帮助开发者提高开发效率和系统稳定性,构建现代、高效、可扩展的应用。
|
6月前
|
存储 监控 安全
【专栏】探讨Docker Compose的核心概念、使用方法及最佳实践,助你轻松驾驭容器编排的世界
【4月更文挑战第27天】Docker Compose是款轻量级容器编排工具,通过YAML文件统一管理多容器应用。本文分三部分深入讨论其核心概念(服务、网络、卷和配置)、使用方法及最佳实践。从快速入门到高级特性,包括环境隔离、CI/CD集成、资源管理和安全措施。通过案例分析展示如何构建多服务应用,助力高效容器编排与管理。
429 2
|
6月前
|
消息中间件 监控 NoSQL
容器化应用系统上生产的最佳实践
容器化应用系统上生产的最佳实践
|
存储 负载均衡 调度
Docker 多主机部署:构建容器集群的最佳实践,助力高可用性与负载均衡
Docker 多主机部署:构建容器集群的最佳实践,助力高可用性与负载均衡
827 0
|
1月前
|
缓存 监控 测试技术
掌握容器化持续集成/持续部署(CI/CD)的最佳实践
【10月更文挑战第8天】本文介绍了容器化持续集成/持续部署(CI/CD)的最佳实践,涵盖容器化CI/CD的概念、优势和实施步骤。通过使用容器技术,可以实现环境一致性、快速迭代和易于扩展,提高软件开发的效率和可靠性。文章还详细讨论了编写高效的Dockerfile、自动化测试、安全性、监控和日志管理等方面的最佳实践。
|
3月前
|
人工智能 Kubernetes 持续交付
Kubernetes环境下基于微服务架构的容器化AI应用部署与管理最佳实践
【8月更文第19天】随着AI技术的快速发展,越来越多的企业开始将AI应用部署到生产环境。然而,AI应用往往包含大量的组件和服务,这使得其部署和管理变得非常复杂。微服务架构和容器化技术(如Docker)结合Kubernetes集群管理,为解决这些问题提供了强大的工具。本文将介绍如何在Kubernetes环境中部署和管理基于微服务架构的容器化AI应用。
188 0
|
5月前
|
机器学习/深度学习 Kubernetes 算法框架/工具
容器服务 ACK 大模型推理最佳实践系列一:TensorRT-LLM
在 ACK 中使用 KServe 部署 Triton+TensorRT-LLM
|
6月前
|
监控 安全 数据库
【Docker专栏】Docker容器化应用的最佳实践
【5月更文挑战第7天】本文介绍了 Docker 容器化应用的关键最佳实践,包括使用官方基础镜像、保持镜像精简、以非 root 用户运行容器、安全扫描、编写高效 Dockerfile、环境隔离、使用数据卷、选择合适网络模式、设置资源限制、使用版本标签、容器编排以及文档和自动化部署。遵循这些实践可提升效率和安全性,同时要注意随着技术发展不断更新知识。
143 10
【Docker专栏】Docker容器化应用的最佳实践
|
6月前
|
Kubernetes 关系型数据库 分布式数据库
【PolarDB开源】PolarDB与Kubernetes集成:容器化部署的最佳实践
【5月更文挑战第21天】本文介绍了将阿里云的高性能数据库PolarDB与容器编排工具Kubernetes集成的步骤。首先,需准备Kubernetes集群和PolarDB Docker镜像,安装Helm。然后,通过Helm部署PolarDB,设置存储类和副本数。接着,应用配置PolarDB连接信息,打包成Docker镜像并在K8s集群中部署。此外,调整PolarDB参数以优化性能,并使用Prometheus和Grafana监控。本文为PolarDB在Kubernetes中的最佳实践提供了指导。
174 4
|
6月前
|
安全 算法 编译器
【C++ 泛型编程 进阶篇】深入探索 C++ STL 容器的嵌套类型:识别、运用与最佳实践
【C++ 泛型编程 进阶篇】深入探索 C++ STL 容器的嵌套类型:识别、运用与最佳实践
157 7
下一篇
无影云桌面