创建容器镜像的艺术和最佳实践

2025-06-04

创建容器镜像的艺术和最佳实践

创建容器镜像的艺术

介绍

我们正处于软件产品开发格局不断发展的时代,因此对高效、一致和可扩展的部署方法的需求变得更加重要。

该领域最重要的进步之一是容器的使用。容器彻底改变了我们构建、打包和部署应用程序的方式,提供了传统方法通常缺乏的灵活性和可靠性。

它是 DevOps 流程自动化 (CI/CD) 中的关键自动化支柱之一,有助于发布已开发的冻结代码。它确保代码在打包到容器镜像后不会发生任何更改。

在本篇博文中,我们将探讨容器的概念,深入探讨传统的应用程序打包方法,并重点介绍创建容器镜像的最佳实践。此外,我们还将提供使用容器打包 React 和 Java 应用程序的示例。


什么是容器?

容器是轻量级、可移植的软件单元,它将应用程序及其依赖项打包在一起,确保其在不同计算环境中一致运行。与虚拟机不同,容器共享主机系统内核,这使得它们在资源利用方面更高效。容器可以在任何支持容器运行时的系统上运行,使其成为现代云原生应用程序开发和部署的理想选择。

Docker诞生

打包应用程序:传统方法

在容器出现之前,应用程序通常使用传统方法打包和部署。这通常需要创建安装包,将应用程序二进制文件以及必要的库和配置文件捆绑在一起。然后,将这些安装包安装到应用程序运行的目标系统上。虽然这种方法多年来一直有效,但它存在一些固有的局限性。

旧方法的缺点

  1. 环境不一致:传统的打包方法经常导致开发、测试和生产环境之间的不一致。这可能会导致应用程序的行为因运行环境而异。开发人员可能会覆盖即将部署到发布环境中的最终软件包,从而导致产品或功能发布的延迟。

  2. 依赖冲突:管理依赖关系是一项重大挑战。不同的应用程序可能需要同一个库的不同版本,这会导致冲突和“依赖地狱”。

  3. 资源开销:传统方法通常需要为每个应用程序提供单独的操作系统实例,从而导致高资源消耗和低效率。

  4. 复杂的部署:部署过程通常很复杂且容易出错,需要手动干预和详细配置。

DevOps 之前和之后

容器如何帮助克服传统方法的不足

容器解决了传统应用程序打包方法的许多缺点:

  1. 一致性:通过将应用程序及其依赖项打包在一起,容器可确保应用程序以相同的方式运行,无论其部署在何处。

  2. 隔离:容器提供进程和文件系统隔离,降低依赖冲突的风险并增强安全性。

  3. 效率:容器共享主机系统的内核和资源,使其比虚拟机更高效。这可以实现更高的密度和更好的资源利用率。

  4. 简化部署:使用 Kubernetes 等容器编排平台,可以轻松部署、扩展和管理容器。这简化了部署流程并降低了出错的风险。


容器镜像创建最佳实践

创建高效安全的容器镜像对于充分利用容器化的优势至关重要。以下是一些值得遵循的最佳实践:

低图像尺寸

  1. 使用最小基础图像:从最小基础图像(例如alpinedistroless)开始,以减小整体图像大小。

  2. 多阶段构建:使用多阶段构建将构建环境与运行时环境分离。这有助于通过排除不必要的构建工具和依赖项来保持最终镜像的轻量级。

  3. 删除不必要的文件:清理镜像构建过程中的临时文件、缓存和其他不必要的文件。

更少/无脆弱图像

  1. 定期更新:定期更新基础图像和依赖项以包含最新的安全补丁和更新。

  2. 安全扫描:在部署图像之前,使用 Trivy 或 Clair 等工具扫描图像中是否存在已知漏洞。

  3. 最小权限:确保应用程序以必要的最小权限运行,以减少潜在的攻击面。

谨慎开放端口

  1. 限制暴露端口:仅暴露应用程序运行所需的端口。避免暴露不必要的端口,以减少攻击面。

  2. 使用非标准端口:尽可能使用非标准端口,以使攻击者更难找到和利用开放服务。

遵循安全最佳实践

  1. 使用非 root 用户:在容器内以非 root 用户身份运行应用程序,以最大限度地减少潜在安全漏洞的影响。

  2. 环境变量:避免在镜像中硬编码敏感信息。使用环境变量在运行时传递敏感数据。

  3. 网络策略:实施网络策略来控制容器之间的流量,增强容器化环境内的安全性。


React 与 Java 应用打包示例

让我们看一下使用 Docker 打包 React 应用程序和基于 Java 的应用程序的示例。

安装 Docker

在创建和推送镜像之前,您需要在计算机上安装 Docker。您可以点击此处,按照您的操作系统的官方 Docker 安装指南进行操作。

打包 React 应用程序

让我们考虑一个基于 React 的 Web 应用程序。容器创建 Dockerfile 如下所示:

  1. Dockerfile

这是一个多阶段 Dockerfile。其中有两个阶段,第 2 阶段依赖于第 1 阶段的构建。

Dockerfile 必须添加到项目主路径中。

```dockerfile
# Stage 1: Build the React app
FROM node:14-alpine as build

WORKDIR /app

COPY package.json ./
COPY package-lock.json ./

RUN npm install

COPY . ./

RUN npm run build

# Stage 2: Serve the React app using Nginx
FROM nginx:alpine

COPY --from=build /app/build /usr/share/nginx/html

EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]
```
Enter fullscreen mode Exit fullscreen mode
  1. 构建并运行

一旦创建了 Docker 文件,我们就可以运行以下命令在用户工作站中创建映像。

```sh
docker build -t my-react-app .
docker run -d -p 80:80 my-react-app
```
Enter fullscreen mode Exit fullscreen mode

打包基于 Java 的应用程序

让我们考虑另一个基于 Java 的 Web 应用。容器创建 Dockerfile 如下所示:

  1. Dockerfile

这也是一个多阶段 Dockerfile。其中有两个阶段:第一阶段构建代码,第二阶段依赖于第一阶段的构建。

Dockerfile 必须添加到项目主路径中。

    # Stage 1: Build the Java app
    FROM maven:3.8.1-jdk-11 as build

    WORKDIR /app

    COPY pom.xml ./
    COPY src ./src

    RUN mvn clean package -DskipTests

    # Stage 2: Run the Java app
    FROM openjdk:11-jre-slim

    COPY --from=build /app/target/my-java-app.jar /app/my-java-app.jar

    EXPOSE 8080

    CMD ["java", "-jar", "/app/my-java-app.jar"]
Enter fullscreen mode Exit fullscreen mode
  1. 构建并运行

一旦创建了 Docker 文件,我们就可以运行以下命令在用户工作站中创建映像。

```sh
docker build -t my-java-app .
docker run -d -p 8080:8080 my-java-app
```
Enter fullscreen mode Exit fullscreen mode

将镜像推送到 Docker Hub 或 Cloud Registry

在本地构建并测试完容器镜像后,通常需要将它们推送到容器镜像仓库进行存储,并部署到其他环境。以下是如何将镜像推送到不同镜像仓库的方法。

将镜像推送到 Docker Hub

  1. 创建 Docker Hub 帐户:如果您还没有帐户,请转到Docker Hub并创建一个帐户。

  2. 登录 Docker Hub

   docker login
Enter fullscreen mode Exit fullscreen mode

系统将提示您输入 Docker Hub 用户名和密码。

  1. 标记您的图片
   docker tag my-image:latest your-dockerhub-username/my-image:latest
Enter fullscreen mode Exit fullscreen mode
  1. 推送图像
   docker push your-dockerhub-username/my-image:latest
Enter fullscreen mode Exit fullscreen mode

将镜像推送到 Google 容器注册表 (GCR)

  1. 设置 GCloud:安装 Google Cloud SDK 并进行身份验证。
   gcloud auth login
   gcloud auth configure-docker
Enter fullscreen mode Exit fullscreen mode
  1. 标记您的图片
   docker tag my-image:latest gcr.io/your-project-id/my-image:latest
Enter fullscreen mode Exit fullscreen mode
  1. 推送图像
   docker push gcr.io/your-project-id/my-image:latest
Enter fullscreen mode Exit fullscreen mode

将图像推送到 Amazon Elastic Container Registry (ECR)

  1. 创建 ECR 存储库:使用 AWS 管理控制台或 CLI 创建存储库。
   aws ecr create-repository --repository-name my-repo
Enter fullscreen mode Exit fullscreen mode
  1. 向您的 ECR 验证 Docker
   aws ecr get-login-password --region your-region | docker login --username AWS --password-stdin your-account-id.dkr.ecr.your-region.amazonaws.com
Enter fullscreen mode Exit fullscreen mode
  1. 标记您的图片
   docker tag my-image:latest your-account-id.dkr.ecr.your-region.amazonaws.com/my-repo:latest
Enter fullscreen mode Exit fullscreen mode
  1. 推送图像
   docker push your-account-id.dkr.ecr.your-region.amazonaws.com/my-repo:latest
Enter fullscreen mode Exit fullscreen mode

将图像推送到 Azure 容器注册表 (ACR)

  1. 创建 ACR:使用 Azure CLI 创建注册表。
   az acr create --resource-group myResourceGroup --name myACR --sku Basic
Enter fullscreen mode Exit fullscreen mode
  1. 登录 ACR
   az acr login --name myACR
Enter fullscreen mode Exit fullscreen mode
  1. 标记您的图片
   docker tag my-image:latest myACR.azurecr.io/my-repo:latest
Enter fullscreen mode Exit fullscreen mode
  1. 推送图像
   docker push myACR.azurecr.io/my-repo:latest
Enter fullscreen mode Exit fullscreen mode

步骤摘要

  1. 创建帐户/存储库:在所需的注册平台上创建一个帐户,并在必要时创建一个存储库。
  2. 登录到注册表:使用 CLI 命令通过注册表验证您的 Docker 客户端。
  3. 标记您的图像:正确标记您的 Docker 图像以匹配注册表的命名约定。
  4. 推送图像:使用docker push命令将您的图像上传到注册表。

结论

容器改变了我们打包和部署应用程序的方式,比传统方法具有显著的优势。

通过遵循容器镜像创建的最佳实践,我们可以构建高效、安全、可靠的容器化应用程序。无论您使用的是 React 等现代 JavaScript 框架,还是更传统的 Java 应用程序,容器化都能简化您的开发和部署流程,确保跨不同环境的一致性和可扩展性。

立即开始利用容器将您的应用程序开发提升到新的水平。

建议的后续步骤

  1. 探索 Kubernetes 等容器编排平台。
  2. 将持续集成和持续部署 (CI/CD) 管道与容器化集成。
  3. 了解用于在容器化环境中管理微服务的服务网格技术。

通过采用这些技术和实践,您可以进一步提高应用程序的效率和可扩展性。

联系我

LinkedIn

GitHub

文章来源:https://dev.to/aws-builders/the-art-of-creating-container-images-and-best-practices-3p9d
PREV
使用 S3、Libvips 和 Ruby 的 AWS Lambda 微服务研讨会
NEXT
AWS 上的无服务器 WebSocket