从 DevOps 角度来看容器与无服务器

2025-05-24

从 DevOps 角度来看容器与无服务器


免责声明:Tracetest赞助了这篇博文。使用可观察性可以将测试创建和故障排除的时间和精力减少 80%。


两个流行词走进酒吧……不?是的,我们别去那里。如果你有这种感觉,那你就来对地方了。容器和无服务器都是过去几年里炙手可热的新兴技术,而且它们的热度丝毫没有减弱的迹象。

在继续之前,我先澄清一下。不,你不会因为无服务器而丢掉 DevOps 的工作。我说完了。我们现在可以继续了吗?谢谢。

TL;DR

  • 为什么这很重要?
  • 什么是容器?
  • 容器的优缺点
  • 容器用例
  • 将容器化的 Node.js 应用程序部署到 AWS 上的 Kubernetes 集群
  • 什么是无服务器?
  • 无服务器的优缺点
  • 无服务器用例
  • 将无服务器 Node.js 应用程序部署到 AWS

注意:如果您想立即查看最终结果,代码示例已经在 GitHub 上,这里这里。

为什么这很重要?

我想告诉你,自己管理容器和让无服务器技术帮你管理容器的利弊。这种“部落战争”必须停止。让我们就几个事实达成共识。这两种技术都有很棒的用例,也都有各自的痛点。我只是想告诉你,什么时候该用什么。

针对这个问题,有几个因素需要考虑。对于初创公司来说,最主要的、最突出的确实是开发速度和上市时间。但是,深入研究后,你会发现还有几个重要的因素需要考虑,比如复杂的部署场景和部署应用程序所需的时间。供应商锁定也是你需要考虑的另一个关键点,尽管我认为这不是什么大问题。但成本才是关键。如果你负责在月底支付基础设施费用,你就会关心你的支出。

准备好学习新知识了吗?让我们开始吧。

什么是容器?

简而言之,容器是隔离的、无状态的环境。容器是一个轻量级的、独立的、可执行的软件包,包含运行该软件所需的一切,包括代码、运行时、系统工具、系统库、设置等。

通过将应用程序及其依赖项容器化,操作系统分布和底层基础设施的差异就被抽象出来了。

我喜欢说它就像一个微型虚拟机,但其实并非如此。大多数开发者都理解虚拟机的概念。我们习惯在虚拟机中运行应用程序。它们模拟真实的机器,拥有真实机器的所有功能。其实,在容器中运行应用程序也是一样的,除了一些重要的架构差异。主要是容器运行在相同的操作系统内核上。让我来演示一下……

这里您可以看到一个清晰的概览。虚拟机使用一种称为虚拟机管理程序的东西。它管理主机上的每个虚拟机。正如您所见,每个虚拟机都有自己的操作系统。而容器共享主机操作系统。这使得容器的体积显著减小,创建和删除速度也更快。

容器的优缺点

在比较容器和无服务器时,根据你的开发者背景和个人情况,其优缺点可能有所不同。不过,我相信可以达成一个双方都能接受的数值。

使用容器意味着默认情况下您将无法使用任何自动扩展功能。您需要自行设置。幸运的是,像 AWS Auto Scaling 这样的供应商专用工具可以简化这一过程。这样做的好处是,您可以完全控制您的资源,并掌控扩展,这意味着理论上您可以拥有无​​限的可扩展性。当然,只要您的提供商允许,您就能拥有无限的可扩展性。

你拥有的所有控制权和权力确实暴露了一个重大缺陷——它带来的复杂性。你需要了解生态系统和各种可用的工具。对很多人来说,这是一个陡峭的学习曲线,因为最终部署和管理应用程序的是你。为了拥有更多的自由和控制权,你必须接受一个事实:应用程序会因各种活动部件而变得复杂。遗憾的是,这会带来更高的成本。毕竟,无论是否有流量,你都在为资源付费。

但并非一切都那么糟糕。它带来的一大好处是,你可以使用众多监控和调试工具。生态系统如此完善,你无需费心设置必要的工具。最后,有了容器,无论你的团队使用哪种操作系统,都能拥有相同的开发环境。这使得大型团队能够轻松高效地工作。

容器用例

容器化应用的用例比无服务器应用更加广泛。主要是因为您可以轻松将现有的单体应用重构为基于容器的架构。但是,为了获得最大收益,您应该将单体应用拆分为独立的微服务。这些微服务将作为独立的容器部署,并配置它们彼此通信。

容器的常见应用包括 Web API、机器学习计算和长时间运行的进程。简而言之,任何你之前使用传统服务器的应用,都非常适合容器化。当你已经为服务器付费,无论负载如何,都要确保它们真正发挥作用。“全力以赴”这个词用得恰如其分。

将容器化的 Node.js 应用程序部署到 AWS 上的 Kubernetes 集群

我们需要关注几个步骤。首先,创建容器镜像并将其推送到仓库。之后,我们需要创建一个 Kubernetes 集群并为容器编写配置文件。最后一步是将所有内容部署到集群并确保其正常运行。

准备好了吗?深呼吸一两口气,这可不是件容易的事。

注意:请确保您的机器上安装了Docker,以便能够运行以下命令。

1. 创建容器镜像

这是一个简单的 Node.js/Express 应用程序。

// app.js
const express = require('express')
const app = express()
app.get('/', async (req, res, next) => {
  res.status(200).send('Hello World!')
})
app.listen(3000, () => console.log('Server is running on port 3000'))
Enter fullscreen mode Exit fullscreen mode

很熟悉吧?用这个创建镜像相当简单。首先,我们需要一个Dockerfile

# Dockerfile
FROM node:alpine

# Create app directory
WORKDIR /usr/src/app

# COPY package.json .
# For npm@5 or later, copy package-lock.json as well
COPY package.json package-lock.json ./

# Install app dependencies
RUN npm install

# Bundle app source
COPY . .

EXPOSE 3000

# Start Node server
CMD [ "npm", "start" ]
Enter fullscreen mode Exit fullscreen mode

这将配置我们的图像是什么样子,要安装的依赖项,它将公开什么端口以及在创建容器后要运行什么命令。

是时候构建图像了。

$ docker build . -t <docker_hub_username>/<image_name>
Enter fullscreen mode Exit fullscreen mode

如果您之前没有构建过镜像,此命令将需要一些时间。完成后,您可以将其推送到容器存储库。我将向您展示 Docker Hub,但您可以使用任何您想要的。

$ docker push <docker_hub_username>/<image_name>
Enter fullscreen mode Exit fullscreen mode

注意:运行此命令之前,请确保已验证您的身份。运行该$ docker login命令。

推送镜像后,Docker Hub 配置文件会列出该镜像。它看起来类似这样。

第一步完成后,您已将镜像拉取到所选的 Kubernetes 集群。接下来,该创建集群了。

2.创建 Kubernetes 集群

在 AWS 上快速启动和运行 Kubernetes 的最简单方法是使用名为KOPS的工具。它是一个用于创建和管理基础设施资源的 CLI。

安装 KOPS 后,您将可以使用 CLI 命令与 Kubernetes 集群交互。以下是一组可快速启动并运行集群的命令。

$ export ORGANIZATION_NAME=your-org-name

# create state store
$ export BUCKET_NAME=${ORGANIZATION_NAME}-state-store
$ aws s3api create-bucket \
    --bucket ${BUCKET_NAME} \
    --region eu-central-1 \
    --create-bucket-configuration LocationConstraint=eu-central-1
$ aws s3api put-bucket-versioning \
    --bucket ${BUCKET_NAME} \
    --versioning-configuration Status=Enabled

# create cluster
$ export KOPS_CLUSTER_NAME=${ORGANIZATION_NAME}.k8s.local
$ export KOPS_STATE_STORE=s3://${BUCKET_NAME}

# define cluster configuration
$ kops create cluster \
    --master-count=1 --master-size=t2.micro \
    --node-count=1 --node-size=t2.micro \
    --zones=eu-central-1a \
    --name=${KOPS_CLUSTER_NAME}

# if you want to edit config
$ kops edit cluster --name ${KOPS_CLUSTER_NAME}

# apply and create cluster
$ kops update cluster --name ${KOPS_CLUSTER_NAME} --yes

# validate cluster is running
$ kops validate cluster
Enter fullscreen mode Exit fullscreen mode

一旦集群运行,您就可以创建用于部署容器映像的配置文件。

3.部署容器镜像

现在我们开始讲解 Kubernetes 的具体内容。使用kubectl命令,你将创建 Kubernetes 资源。为了快速上手,你需要一个部署 (Deployment) 和一个服务 (Service)。为了方便起见,我们创建两个 YAML 文件。一个用于部署,一个用于服务。

# node-deployment.yml
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: node
spec:
  selector:
    matchLabels:
      app: node
      tier: backend
  replicas: 9
  template:
    metadata:
      labels:
        app: node
        tier: backend
    spec:
      containers:
        - name: node
          image: <docker_hub_username>/<image_name>
          ports:
            - containerPort: 3000
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
Enter fullscreen mode Exit fullscreen mode

部署将创建 pod、副本集并确保它们正常工作,同时服务将部署暴露给外部流量。

# node-service.yml
apiVersion: v1
kind: Service
metadata:
  name: node
  labels:
    app: node
    tier: backend
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 3000
  selector:
    app: node
    tier: backend
Enter fullscreen mode Exit fullscreen mode

现在您可以运行kubectl命令。

$ kubectl apply -f node-deployment.yml
$ kubectl apply -f node-service.yml
Enter fullscreen mode Exit fullscreen mode

这将创建 Pod、副本集、部署和服务。太棒了!现在你可以看到应用程序正在运行。理想情况下,一旦你将代码推送到代码仓库,整个过程就会在 CI/CD 流水线中自动完成。但是,即使对于之前做过这件事的人来说,这个过程也相当漫长。

让我们看看无服务器的比较情况。

注意:您可以在此 GitHub 仓库中查看此配置。如果您希望更多人看到它,请点个星标。

什么是无服务器?

从定义上讲,无服务器通常被认为是函数即服务 (FaaS)。但这并非完全正确。无服务器远不止于此。它应该被视为一个基于事件的代码运行系统。这意味着,您可以使用各种服务来创建业务逻辑,而无需关心任何服务器。您正在完全抽象基础设施。完美的例子包括将静态网站托管在 S3 上,使用 DynamoDB 或 Aurora Serverless 等无服务器数据库,当然还有使用 Lambda 无需管理服务器即可运行代码。

如果您遇到突发流量高峰,需要立即检测并处理,那么无服务器架构是理想之选。即使没有任何流量,应用程序也会完全关闭。您只需按实际使用的资源付费。无使用量,无需支付任何费用。

无服务器的优缺点

提到无服务器,首先想到的就是无需管理任何基础设施。无需安装操作系统更新,无需安全补丁,无需担心,因为提供商会帮您搞定一切。这比管理自己的基础设施和集群要简单得多。然而,这种魔力是有代价的。使用 Kubernetes 轻松为应用添加可观察性,但无服务器却无法做到这一点。您需要依赖 OpenTelemetry 等工具进行仪表盘和可观察性供应商,但更重要的是,需要使用Tracetest之类的工具进行故障排除和端到端测试。

对于我的许多开发者同行来说,自动伸缩功能带来的便利是无比的。它默认启用,无需任何配置,它就能正常工作。由于应用程序在没有流量时会完全关闭,因此成本非常低廉。但并非所有功能都完美无缺。您必须忍受明确的处理能力和内存限制,这迫使您编写更高效的代码,因为如果函数规模过大,可能会过载。这还可能导致可怕的噩梦——延迟。😞

关于延迟,FaaS 解决方案存在所谓的冷启动问题。函数的首次调用大约需要一两秒钟才能让容器启动。如果这是一个问题,你应该重新考虑是否使用 FaaS。

然而,部署的简易性才是无服务器架构的精髓所在。您只需将代码部署到提供商处即可运行。无需 Dockerfile 或 Kubernetes 配置。您的产品上市速度将非常快,而这正是初创公司最看重的。

无服务器用例

我相信你已经可以通过阅读这些优缺点得出关于用例的结论。无服务器非常适合微服务架构。这些微服务可以是简单的 Web API 或任务运行器。无服务器函数的短暂性使其成为处理数据流或图像的理想选择。

您还可以将它们用作 Cron 作业,安排函数每天在特定时间运行。无需让服务器始终运行,只需偶尔运行后台任务即可。请记住,FaaS 仅适用于短时间运行的进程。AWS Lambda 函数的最长运行时间为 15 分钟。如果您有一些繁重的计算任务,我建议您改用基于容器的设置。

将无服务器 Node.js 应用程序部署到 AWS

你会惊讶地发现,将 Node.js 应用部署到无服务器环境的步骤明显减少了许多吗?我当然希望你不会。

借助无服务器框架,您可以大大简化无服务器应用程序的开发流程。您可以在名为serverless.yml的文件中配置所有资源。它本质上会被转换为 CloudFormation 模板,部署到 AWS 并创建您指定的所有资源。代码本身会被打包成 .zip 文件并上传到 S3。之后,它将被部署到 Lambda。

无服务器框架的神奇之处在于,它实现了一步到位的自动化资源创建和代码部署。让我来演示一下。

注意:我假设您已经安装并配置了所需的框架模块和 ​​IAM 角色。如果没有,请查看此处以开始使用。

# Framework
$ npm i -g serverless 
# Express.js router proxy module
$ npm i serverless-http
Enter fullscreen mode Exit fullscreen mode

1. 配置无服务器资源

以下是相同的 Node.js/Express 的外观,经过微小修改后可与 AWS Lambda 配合使用。

// app.js
const express = require('express')
const sls = require('serverless-http')
const app = express()
app.get('/', async (req, res, next) => {
  res.status(200).send('Hello World!')
})
module.exports.server = sls(app)
Enter fullscreen mode Exit fullscreen mode

唯一的区别是,你将其传递给了serverless-http模块。接下来,我想让你深入了解我们所需的实际资源,让我们查看一个示例serverless.yml文件。

# serverless.yml
service: express-sls-app

provider:
  name: aws
  runtime: nodejs8.10
  stage: dev
  region: eu-central-1

functions:
  app:
    handler: app.server
    events:
      - http:
          path: /
          method: ANY
      - http:
          path: /{proxy+}
          method: ANY
Enter fullscreen mode Exit fullscreen mode

我们将部署一个app函数,其函数处理程序指向app.jsserver文件中的方法。此函数的事件触发器将是向任意路径发出的 HTTP 请求。实际的路由将在 Express 应用内部处理,因此我们只需添加设置即可。{proxy+}

2. 部署无服务器资源

猜猜看,将所有内容部署到 AWS 只需要一个命令。

$ serverless deploy
Enter fullscreen mode Exit fullscreen mode

创建一个可行的 CI/CD 管道来运行单个命令比容器命令的荒野丛林要简单得多。

注意:您可以在此 GitHub 仓库中查看此配置。如果您希望更多人看到它,请点个星标。

总结

这里的关键点是什么?何时选择什么?当你需要灵活性和对系统的完全控制,或者需要迁移遗留服务时,我建议你选择容器和容器编排器,比如Kubernetes 。

当您需要更快的开发速度、自动扩展以及显著降低的运行时成本时,无服务器是更好的选择。无服务器还可以作为支持服务与遗留系统绑定,这些支持服务是在主代码库之外开发的,用于处理特定问题或业务逻辑。无服务器框架在这方面为您提供了极大的帮助。

有了容器,监控和适当的警报已经通过Prometheus等工具足够成熟,而无服务器则落后了。

无服务器社区里有一些很棒的文章,你可以看看。它们都解释了这两种技术的优势,并解释了为什么容器和无服务器之间的那些小争吵毫无意义。我建议你去看看!

如果您想阅读我之前的一些无服务器思考,请转到 我的个人资料 或 加入我的无服务器时事通讯!

我写这篇文章的时候非常开心,希望你们读起来和我写的时候一样开心。如果你们喜欢,就拍拍那只小独角兽,这样 dev.to 上会有更多人看到这篇文章。下次再见,保持好奇心,玩得开心。

:我十月份会在 WebCampZagreb上就这个话题做个演讲。如果你在附近,欢迎来参加。😊


免责声明:Tracetest赞助了这篇博文。使用可观察性可以将测试创建和故障排除的时间和精力减少 80%。


文章来源:https://dev.to/adnanrahic/containers-vs-serverless-from-a-devops-standpoint-e4n
PREV
如何使用 i18next 正确地国际化 React 应用程序 首先:“为什么要使用 i18next?” 让我们开始吧……🎉🥳 恭喜 🎊🎁 👍
NEXT
使用 React.js、Next.js 和 AWS Lambda 进行无服务器端渲染的速成课程 无服务器端渲染 React Next