如何将用于Rails开发的DockerCompose工作流迁移到Kubernetes
介绍
在构建现代的无状态应用程序时, 将应用程序的组件容器化 是在分布式平台上部署和扩展的第一步。 如果您在开发中使用了 Docker Compose,您将通过以下方式对您的应用程序进行现代化和容器化:
- 从代码中提取必要的配置信息。
- 卸载应用程序的状态。
- 打包您的应用程序以供重复使用。
您还将编写指定容器映像应如何运行的服务定义。
要在 Kubernetes 等分布式平台上运行您的服务,您需要将 Compose 服务定义转换为 Kubernetes 对象。 这将允许您 以弹性 扩展您的应用程序。 kompose 是一种可以加快向 Kubernetes 的转换过程的工具,它是一种转换工具,可帮助开发人员将 Compose 工作流迁移到 Kubernetes 或 OpenShift 等容器编排器。
在本教程中,您将使用 kompose 将 Compose 服务转换为 Kubernetes objects。 您将使用 kompose 提供的对象定义作为起点并进行调整,以确保您的设置将使用 Secrets、Services 和 PersistentVolumeClaims Kubernetes 所期望的。 在本教程结束时,您将拥有一个单实例 Rails 应用程序,其中包含在 Kubernetes 集群上运行的 PostgreSQL 数据库。 此设置将反映 使用 Docker Compose 将 Ruby on Rails 应用程序容器化以进行开发 中描述的代码的功能,并将成为构建可根据您的需求扩展的生产就绪解决方案的良好起点。
先决条件
- 启用了基于角色的访问控制 (RBAC) 的 Kubernetes 1.19+ 集群。 此设置将使用 DigitalOcean Kubernetes 集群,但您可以自由地 使用另一种方法 创建集群。
kubectl
命令行工具安装在您的本地机器或开发服务器上并配置为连接到您的集群。 您可以在官方文档中阅读更多关于安装kubectl
的信息。- Docker 安装在本地机器或开发服务器上。 如果您使用的是 Ubuntu 20.04,请按照 如何在 Ubuntu 20.04 上安装和使用 Docker 的步骤 1 和 2; 否则,请按照 官方文档 了解有关在其他操作系统上安装的信息。 确保将您的非 root 用户添加到
docker
组,如链接教程的第 2 步所述。 - 一个 Docker Hub 帐户。 有关如何设置的概述,请参阅 this Introduction to Docker Hub。
第 1 步 — 安装 kompose
要开始使用 kompose,请导航到 项目的 GitHub 发布页面 ,然后将链接复制到当前版本(撰写本文时版本 1.22.0)。 将此链接粘贴到以下 curl
命令中以下载最新版本的 kompose:
curl -L https://github.com/kubernetes/kompose/releases/download/v1.22.0/kompose-linux-amd64 -o kompose
关于在非Linux系统上安装的详细信息,请参考【X71X】安装说明【X100X】。
使二进制可执行文件:
chmod +x kompose
将其移至您的 PATH
:
sudo mv ./kompose /usr/local/bin/kompose
要验证它是否已正确安装,您可以进行版本检查:
kompose version
如果安装成功,您将看到如下输出:
Output1.22.0 (955b78124)
安装 kompose
并准备好使用后,您现在可以克隆您将要翻译到 Kubernetes 的 Node.js 项目代码。
第 2 步 — 克隆和打包应用程序
要将我们的应用程序与 Kubernetes 一起使用,我们需要克隆项目代码并打包应用程序,以便 kubelet
服务可以拉取镜像。
我们的第一步是从 DigitalOcean 社区 GitHub 帐户 克隆 rails-sidekiq 存储库。 此存储库包含 Containerizing a Ruby on Rails Application for Development with Docker Compose 中描述的设置中的代码,它使用演示 Rails 应用程序来演示如何使用 Docker Compose 设置开发环境。 您可以在 Rails on Containers 系列中找到有关应用程序本身的更多信息。
将存储库克隆到名为 rails_project
的目录中:
git clone https://github.com/do-community/rails-sidekiq.git rails_project
导航到 rails_project
目录:
cd rails_project
现在从 compose-workflow
分支检查本教程的代码:
git checkout compose-workflow
OutputBranch 'compose-workflow' set up to track remote branch 'compose-workflow' from 'origin'. Switched to a new branch 'compose-workflow'
rails_project
目录包含用于处理用户输入的鲨鱼信息应用程序的文件和目录。 它经过现代化改造,可以与容器一起使用:敏感和特定的配置信息已从应用程序代码中删除,并重构为在运行时注入,应用程序的状态已卸载到 PostgreSQL 数据库。
有关设计现代无状态应用程序的更多信息,请参阅 为 Kubernetes 构建应用程序 和 为 Kubernetes 现代化应用程序。
项目目录包含一个 Dockerfile
,其中包含构建应用程序映像的说明。 现在让我们构建映像,以便您可以将其推送到您的 Docker Hub 帐户并在您的 Kubernetes 设置中使用它。
使用 docker build 命令,使用 -t
标志构建映像,这允许您使用易于记忆的名称对其进行标记。 在这种情况下,使用您的 Docker Hub 用户名标记图像并将其命名为 rails-kubernetes
或您自己选择的名称:
docker build -t your_dockerhub_user/rails-kubernetes .
命令中的 .
指定构建上下文是当前目录。
构建映像需要一两分钟。 完成后,检查您的图像:
docker images
您将看到以下输出:
OutputREPOSITORY TAG IMAGE ID CREATED SIZE your_dockerhub_user/rails-kubernetes latest 24f7e88b6ef2 2 days ago 606MB alpine latest d6e46aa2470d 6 weeks ago 5.57MB
接下来,登录到您在先决条件中创建的 Docker Hub 帐户:
docker login -u your_dockerhub_user
出现提示时,输入您的 Docker Hub 帐户密码。 以这种方式登录将使用您的 Docker Hub 凭据在用户的主目录中创建一个 ~/.docker/config.json
文件。
使用 docker push 命令 将应用程序镜像推送到 Docker Hub。 请记住将 your_dockerhub_user
替换为您自己的 Docker Hub 用户名:
docker push your_dockerhub_user/rails-kubernetes
您现在有一个应用程序映像,您可以拉取该映像以使用 Kubernetes 运行您的应用程序。 下一步是将您的应用程序服务定义转换为 Kubernetes 对象。
第 3 步 — 使用 kompose 将 Compose 服务转换为 Kubernetes 对象
我们的 Docker Compose 文件(此处称为 docker-compose.yml
)列出了将使用 Compose 运行我们的服务的定义。 Compose 中的 服务 是一个正在运行的容器,而 服务定义 包含有关每个容器映像将如何运行的信息。 在这一步中,我们将通过使用 kompose
创建 yaml
文件将这些定义转换为 Kubernetes 对象。 这些文件将包含 Kubernetes 对象的 specs,描述它们的 期望状态 。
我们将使用这些文件来创建不同类型的对象:Services,这将确保运行我们容器的 Pods 保持可访问性; Deployments,它将包含有关我们的 Pod 所需状态的信息; PersistentVolumeClaim 为我们的数据库数据提供存储; 一个 ConfigMap 用于在运行时注入的环境变量; 以及我们应用程序的数据库用户和密码的 Secret。 其中一些定义将在 kompose
将为我们创建的文件中,而其他定义将需要我们自己创建。
首先,我们需要修改 docker-compose.yml
文件中的一些定义以使用 Kubernetes。 我们将在我们的 app
服务定义中包含对我们新建应用程序映像的引用,并删除 绑定 mounts、volumes 和其他 命令[X183X ] 我们曾经使用 Compose 在开发中运行应用程序容器。 此外,我们将重新定义两个容器的重启策略以符合 Kubernetes 期望的行为 。
如果您按照本教程中的步骤操作并使用 git 检查了 compose-workflow
分支,那么您的工作目录中应该有一个 docker-compose.yml
文件。
如果您没有 docker-compose.yml
,请务必访问本系列的上一篇教程,Containerizing a Ruby on Rails Application for Development with Docker Compose,并粘贴链接中的内容节到一个新的 docker-compose.yml
文件。
使用 nano
或您喜欢的编辑器打开文件:
nano docker-compose.yml
app
应用程序服务的当前定义如下所示:
~/rails_project/docker-compose.yml
. . . services: app: build: context: . dockerfile: Dockerfile depends_on: - database - redis ports: - "3000:3000" volumes: - .:/app - gem_cache:/usr/local/bundle/gems - node_modules:/app/node_modules env_file: .env environment: RAILS_ENV: development . . .
对您的服务定义进行以下编辑:
- 将
build:
行替换为image: your_dockerhub_user/rails-kubernetes
- 删除以下
context: .
和dockerfile: Dockerfile
行。 - 删除
volumes
列表。
完成的服务定义现在将如下所示:
~/rails_project/docker-compose.yml
. . . services: app: image: your_dockerhub_user/rails-kubernetes depends_on: - database - redis ports: - "3000:3000" env_file: .env environment: RAILS_ENV: development . . .
接下来,向下滚动到 database
服务定义并进行以下编辑:
- 移除
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
音量线。 我们将使用我们将在 Step 4 中创建的 Secret 将POSTGRES_USER
和POSTGRES_PASSWORD
的值传递给数据库容器,而不是使用本地 SQL 文件中的值。 - 添加一个
ports:
部分,这将使 PostgreSQL 在 Kubernetes 集群中的端口 5432 上可用。 - 添加带有
PGDATA
变量的environment:
部分,该变量指向/var/lib/postgresql/data
内的目录。 当 PostgreSQL 配置为使用块存储时,此设置是必需的,因为数据库引擎希望在子目录中找到其数据文件。
完成编辑后,database
服务定义应如下所示:
~/rails_project/docker-compose.yml
. . . database: image: postgres:12.1 volumes: - db_data:/var/lib/postgresql/data ports: - "5432:5432" environment: PGDATA: /var/lib/postgresql/data/pgdata . . .
接下来,编辑 redis
服务定义以通过添加具有默认 6379 端口的 ports:
部分来公开其默认 TCP 端口。 添加 ports:
部分将使 Redis 在您的 Kubernetes 集群中可用。 您编辑的 redis
服务应类似于以下内容:
~/rails_project/docker-compose.yml
. . . redis: image: redis:5.0.7 ports: - "6379:6379"
编辑文件的 redis
部分后,继续 sidekiq
服务定义。 与 app
服务一样,您需要从构建本地 docker 映像切换到从 Docker Hub 拉取。 对您的 sidekiq
服务定义进行以下编辑:
- 将
build:
行替换为image: your_dockerhub_user/rails-kubernetes
- 删除以下
context: .
和dockerfile: Dockerfile
行。 - 删除
volumes
列表。
~/rails_project/docker-compose.yml
. . . sidekiq: image: your_dockerhub_user/rails-kubernetes depends_on: - app - database - redis env_file: .env environment: RAILS_ENV: development entrypoint: ./entrypoints/sidekiq-entrypoint.sh
最后,在文件底部,从顶级 volumes
键中删除 gem_cache
和 node_modules
卷。 密钥现在看起来像这样:
~/rails_project/docker-compose.yml
. . . volumes: db_data:
完成编辑后保存并关闭文件。
作为参考,您完成的 docker-compose.yml
文件应包含以下内容:
~/rails_project/docker-compose.yml
version: '3' services: app: image: your_dockerhub_user/rails-kubernetes depends_on: - database - redis ports: - "3000:3000" env_file: .env environment: RAILS_ENV: development database: image: postgres:12.1 volumes: - db_data:/var/lib/postgresql/data ports: - "5432:5432" environment: PGDATA: /var/lib/postgresql/data/pgdata redis: image: redis:5.0.7 ports: - "6379:6379" sidekiq: image: your_dockerhub_user/rails-kubernetes depends_on: - app - database - redis env_file: .env environment: RAILS_ENV: development entrypoint: ./entrypoints/sidekiq-entrypoint.sh volumes: db_data:
在翻译我们的服务定义之前,我们需要编写 .env
文件,kompose
将使用我们的非敏感信息创建 ConfigMap。 请参阅 Containerizing a Ruby on Rails Application for Development with Docker Compose 的 Step 2 以了解此文件的详细说明。
在那个教程中,我们将 .env
添加到我们的 .gitignore
文件中,以确保它不会复制到版本控制中。 这意味着当我们在本教程的 步骤 2 中克隆 rails-sidekiq 存储库 时,它没有复制过来。 因此,我们现在需要重新创建它。
创建文件:
nano .env
kompose
将使用此文件为我们的应用程序创建一个 ConfigMap。 但是,我们不会从 Compose 文件中的 app
服务定义中分配所有变量,而是仅添加 PostgreSQL 和 Redis 的设置。 在Step 4手动创建Secret对象时,我们将分别分配数据库名称、用户名和密码。
将以下端口和数据库名称信息添加到 .env
文件中。 如果您愿意,请随意重命名您的数据库:
~/rails_project/.env
DATABASE_HOST=database DATABASE_PORT=5432 REDIS_HOST=redis REDIS_PORT=6379
完成编辑后保存并关闭文件。
您现在已准备好使用您的对象规范创建文件。 kompose
提供 多种选项 用于翻译您的资源。 你可以:
- 根据
docker-compose.yml
文件和kompose convert
中的服务定义创建yaml
文件。 - 直接使用
kompose up
创建 Kubernetes 对象。 - 使用
kompose convert -c
创建一个 Helm 图表。
现在,我们将我们的服务定义转换为 yaml
文件,然后添加和修改 kompose
创建的文件。
使用以下命令将您的服务定义转换为 yaml
文件:
kompose convert
运行此命令后,kompose 将输出有关它创建的文件的信息:
OutputINFO Kubernetes file "app-service.yaml" created INFO Kubernetes file "database-service.yaml" created INFO Kubernetes file "redis-service.yaml" created INFO Kubernetes file "app-deployment.yaml" created INFO Kubernetes file "env-configmap.yaml" created INFO Kubernetes file "database-deployment.yaml" created INFO Kubernetes file "db-data-persistentvolumeclaim.yaml" created INFO Kubernetes file "redis-deployment.yaml" created INFO Kubernetes file "sidekiq-deployment.yaml" created
其中包括 yaml
文件,其中包含 Rails 应用程序服务、部署和 ConfigMap 以及 db-data
PersistentVolumeClaim 和 PostgreSQL 数据库部署的规范。 还包括分别用于 Redis 和 Sidekiq 的文件。
要将这些清单保存在 Rails 项目的主目录之外,请创建一个名为 k8s-manifests
的新目录,然后使用 mv
命令将生成的文件移动到其中:
mkdir k8s-manifests mv *.yaml k8s-manifests
最后将cd
放到k8s-manifests
目录下。 从现在开始,我们将在此目录中工作以保持整洁:
cd k8s-manifests
这些文件是一个很好的起点,但是为了使我们的应用程序的功能与 Containerizing a Ruby on Rails Application for Development with Docker Compose 中描述的设置相匹配,我们需要对kompose
生成的文件。
第 4 步 — 创建 Kubernetes 机密
为了让我们的应用程序以我们期望的方式运行,我们需要对 kompose
创建的文件进行一些修改。 这些更改中的第一个将为我们的数据库用户和密码生成一个 Secret,并将其添加到我们的应用程序和数据库部署中。 Kubernetes 提供了两种使用环境变量的方式:ConfigMaps 和 Secrets。 kompose
已经使用我们在 .env
文件中包含的非机密信息创建了一个 ConfigMap,因此我们现在将使用我们的机密信息创建一个 Secret:我们的数据库名称、用户名和密码。
手动创建 Secret 的第一步是将数据转换为 base64,这是一种允许您统一传输数据(包括二进制数据)的编码方案。
首先将数据库名称转换为base64编码数据:
echo -n 'your_database_name' | base64
记下编码值。
接下来转换您的数据库用户名:
echo -n 'your_database_username' | base64
再次记录您在输出中看到的值。
最后,转换您的密码:
echo -n 'your_database_password' | base64
还要注意此处输出中的值。
打开 Secret 文件:
nano secret.yaml
注意:Kubernetes对象是通常使用YAML定义,严格禁止制表符,缩进需要两个空格。 如果您想检查任何 yaml
文件的格式,可以使用 linter 或使用 kubectl create
和 --dry-run
和 --validate
标志:
kubectl create -f your_yaml_file.yaml --dry-run --validate=true
通常,在使用 kubectl
创建资源之前验证您的语法是个好主意。
将以下代码添加到文件中以创建一个 Secret,它将使用您刚刚创建的编码值定义您的 DATABASE_NAME
、DATABASE_USER
和 DATABASE_PASSWORD
。 请务必将此处突出显示的占位符值替换为您的 编码 数据库名称、用户名和密码:
~/rails_project/k8s-manifests/secret.yaml
apiVersion: v1 kind: Secret metadata: name: database-secret data: DATABASE_NAME: your_database_name DATABASE_PASSWORD: your_encoded_password DATABASE_USER: your_encoded_username
我们已将 Secret 对象命名为 database-secret
,但您可以随意命名它。
这些机密与 Rails 应用程序一起使用,以便它可以连接到 PostgreSQL。 但是,数据库本身需要使用这些相同的值进行初始化。 所以接下来,复制这三行并将它们粘贴到文件末尾。 编辑最后三行并将每个变量的 DATABASE
前缀更改为 POSTGRES
。 最后将POSTGRES_NAME
变量改为POSTGRES_DB
。
您的最终 secret.yaml
文件应包含以下内容:
~/rails_project/k8s-manifests/secret.yaml
apiVersion: v1 kind: Secret metadata: name: database-secret data: DATABASE_NAME: your_database_name DATABASE_PASSWORD: your_encoded_password DATABASE_USER: your_encoded_username POSTGRES_DB: your_database_name POSTGRES_PASSWORD: your_encoded_password POSTGRES_USER: your_encoded_username
完成编辑后保存并关闭此文件。 正如您对 .env
文件所做的那样,请务必将 secret.yaml
添加到 .gitignore
文件中以使其不受版本控制。
编写 secret.yaml
后,下一步将确保我们的应用程序和数据库部署都使用我们添加到文件中的值。 让我们首先将对 Secret 的引用添加到我们的应用程序部署中。
打开名为 app-deployment.yaml
的文件:
nano app-deployment.yaml
该文件的容器规范包括在 env
键下定义的以下环境变量:
~/rails_project/k8s-manifests/app-deployment.yaml
apiVersion: apps/v1 kind: Deployment . . . spec: containers: - env: - name: DATABASE_HOST valueFrom: configMapKeyRef: key: DATABASE_HOST name: env - name: DATABASE_PORT valueFrom: configMapKeyRef: key: DATABASE_PORT name: env - name: RAILS_ENV value: development - name: REDIS_HOST valueFrom: configMapKeyRef: key: REDIS_HOST name: env - name: REDIS_PORT valueFrom: configMapKeyRef: key: REDIS_PORT name: env . . .
我们需要添加对 Secret 的引用,以便我们的应用程序可以访问这些值。 我们将包含一个 secretKeyRef
键来指向我们的 env
ConfigMap,而不是包含一个 configMapKeyRef
键来指向我们的值我们的 database-secret
秘密。
在 - name: REDIS_PORT
变量部分之后添加以下 Secret 引用:
~/rails_project/k8s-manifests/app-deployment.yaml
. . . spec: containers: - env: . . . - name: REDIS_PORT valueFrom: configMapKeyRef: key: REDIS_PORT name: env - name: DATABASE_NAME valueFrom: secretKeyRef: name: database-secret key: DATABASE_NAME - name: DATABASE_PASSWORD valueFrom: secretKeyRef: name: database-secret key: DATABASE_PASSWORD - name: DATABASE_USER valueFrom: secretKeyRef: name: database-secret key: DATABASE_USER . . .
完成编辑后保存并关闭文件。 与您的 secrets.yaml
文件一样,请务必使用 kubectl
验证您的编辑,以确保空格、制表符和缩进没有问题:
kubectl create -f app-deployment.yaml --dry-run --validate=true
Outputdeployment.apps/app created (dry run)
接下来,我们将相同的值添加到 database-deployment.yaml
文件中。
打开文件进行编辑:
nano database-deployment.yaml
在此文件中,我们将为以下变量键添加对 Secret 的引用:POSTGRES_DB
、POSTGRES_USER
和 POSTGRES_PASSWORD
。 postgres
图像使这些变量可用,以便您可以修改数据库实例的初始化。 POSTGRES_DB
创建容器启动时可用的默认数据库。 POSTGRES_USER
和 POSTGRES_PASSWORD
共同创建一个可以访问创建的数据库的特权用户。
使用这些值意味着我们创建的用户可以访问该角色在 PostgreSQL 中的所有管理和操作权限。 在生产中工作时,您需要创建一个具有适当范围权限的专用应用程序用户。
在 POSTGRES_DB
、POSTGRES_USER
和 POSTGRES_PASSWORD
变量下,添加对 Secret 值的引用:
~/rails_project/k8s-manifests/database-deployment.yaml
apiVersion: apps/v1 kind: Deployment . . . spec: containers: - env: - name: PGDATA value: /var/lib/postgresql/data/pgdata - name: POSTGRES_DB valueFrom: secretKeyRef: name: database-secret key: POSTGRES_DB - name: POSTGRES_PASSWORD valueFrom: secretKeyRef: name: database-secret key: POSTGRES_PASSWORD - name: POSTGRES_USER valueFrom: secretKeyRef: name: database-secret key: POSTGRES_USER . . .
完成编辑后保存并关闭文件。 再次确保使用带有 --dry-run --validate=true
参数的 kubectl
对您编辑的文件进行 lint。
有了 Secret,您可以继续创建数据库服务,并确保您的应用程序容器仅在完全设置和初始化后才尝试连接到数据库。
第 5 步 — 修改 PersistentVolumeClaim 并公开应用程序前端
在运行我们的应用程序之前,我们将进行两项最终更改,以确保我们的数据库存储将被正确配置,并且我们可以使用 LoadBalancer 公开我们的应用程序前端。
首先,让我们修改 kompose 为我们创建的 PersistentVolumeClaim 中定义的 storage
resource。 这个声明允许我们动态配置存储来管理我们应用程序的状态。
要使用 PersistentVolumeClaims,您必须创建并配置一个 StorageClass 以供应存储资源。 在我们的例子中,因为我们正在使用 DigitalOcean Kubernetes,我们的默认 StorageClass provisioner
设置为 dobs.csi.digitalocean.com
— DigitalOcean Block Storage。
我们可以通过键入以下内容进行检查:
kubectl get storageclass
如果您使用的是 DigitalOcean 集群,您将看到以下输出:
OutputNAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE do-block-storage (default) dobs.csi.digitalocean.com Delete Immediate true 76m
如果您不使用 DigitalOcean 集群,则需要创建一个 StorageClass 并配置您选择的 provisioner
。 具体操作方法请参见【X49X】官方文档【X75X】。
当 kompose
创建 db-data-persistentvolumeclaim.yaml
时,它将 storage
resource
设置为不符合我们的 provisioner
的最小尺寸要求的尺寸。 因此,我们需要修改 PersistentVolumeClaim 以使用 最小可行的 DigitalOcean 块存储单元 :1GB。 请随意修改它以满足您的存储要求。
打开db-data-persistentvolumeclaim.yaml
:
nano db-data-persistentvolumeclaim.yaml
将 storage
值替换为 1Gi
:
~/rails_project/k8s-manifests/db-data-persistentvolumeclaim.yaml
apiVersion: v1 kind: PersistentVolumeClaim metadata: creationTimestamp: null labels: io.kompose.service: db-data name: db-data spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi status: {}
另请注意 accessMode
:ReadWriteOnce
表示由于此声明而配置的卷将只能由单个节点读写。 有关不同访问模式的更多信息,请参阅 文档。
完成后保存并关闭文件。
接下来,打开app-service.yaml
:
nano app-service.yaml
我们将使用 DigitalOcean 负载平衡器 在外部公开此服务。 如果您没有使用 DigitalOcean 集群,请查阅您的云提供商的相关文档以获取有关其负载均衡器的信息。 或者,您可以按照 Kubernetes 官方文档 使用 kubeadm 设置高可用性集群,但在这种情况下,您将无法使用 PersistentVolumeClaims 来配置存储。
在服务规范中,将 LoadBalancer
指定为服务 type
:
~/rails_project/k8s-manifests/app-service.yaml
apiVersion: v1 kind: Service . . . spec: type: LoadBalancer ports: . . .
当我们创建 app
服务时,将自动创建一个负载均衡器,为我们提供一个外部 IP,我们可以访问我们的应用程序。
完成编辑后保存并关闭文件。
准备好所有文件后,我们就可以开始并测试应用程序了。
注意: 如果您想将您编辑的 Kubernetes 清单与一组参考文件进行比较,以确保您的更改与本教程相匹配, 配套 Github 存储库 包含一组经过测试的清单. 您可以单独比较每个文件,也可以切换本地 git 分支以使用 kubernetes-workflow
分支。
如果您选择切换分支,请务必将您的 secrets.yaml
文件复制到新签出的版本中,因为我们在本教程的前面将其添加到 .gitignore
中。
第 6 步 — 启动和访问应用程序
是时候创建我们的 Kubernetes 对象并测试我们的应用程序是否按预期工作了。
要创建我们定义的对象,我们将使用带有 -f
标志的 kubectl create,这将允许我们指定 kompose
为我们创建的文件,连同我们编写的文件。 运行以下命令来创建 Rails 应用程序和 PostgreSQL 数据库、Redis 缓存和 Sidekiq 服务和部署,以及您的 Secret、ConfigMap 和 PersistentVolumeClaim:
kubectl create -f app-deployment.yaml,app-service.yaml,database-deployment.yaml,database-service.yaml,db-data-persistentvolumeclaim.yaml,env-configmap.yaml,redis-deployment.yaml,redis-service.yaml,secret.yaml,sidekiq-deployment.yaml
您会收到以下输出,表明对象已创建:
Outputdeployment.apps/app created service/app created deployment.apps/database created service/database created persistentvolumeclaim/db-data created configmap/env created deployment.apps/redis created service/redis created secret/database-secret created deployment.apps/sidekiq created
要检查您的 Pod 是否正在运行,请键入:
kubectl get pods
您无需在此处指定 Namespace,因为我们已经在 default
命名空间中创建了对象。 如果您正在使用多个命名空间,请确保在运行此 kubectl create
命令时包含 -n
标志以及命名空间的名称。
当您的 database
容器正在启动时,您将看到类似于以下的输出(状态将为 Pending
或 ContainerCreating
):
OutputNAME READY STATUS RESTARTS AGE app-854d645fb9-9hv7w 1/1 Running 0 23s database-c77d55fbb-bmfm8 0/1 Pending 0 23s redis-7d65467b4d-9hcxk 1/1 Running 0 23s sidekiq-867f6c9c57-mcwks 1/1 Running 0 23s
启动数据库容器后,您将获得如下输出:
OutputNAME READY STATUS RESTARTS AGE app-854d645fb9-9hv7w 1/1 Running 0 30s database-c77d55fbb-bmfm8 1/1 Running 0 30s redis-7d65467b4d-9hcxk 1/1 Running 0 30s sidekiq-867f6c9c57-mcwks 1/1 Running 0 30s
Running
STATUS
表示您的 Pod 已绑定到节点,并且与这些 Pod 关联的容器正在运行。 READY
表示一个 Pod 中有多少个容器正在运行。 有关详细信息,请参阅有关 Pod 生命周期的 文档。
注意: 如果您在 STATUS
列中看到意外的阶段,请记住您可以使用以下命令对 Pod 进行故障排除:
kubectl describe pods your_pod kubectl logs your_pod
现在您的应用程序已启动并运行,最后一步是运行 Rails 的数据库迁移。 此步骤会将模式加载到演示应用程序的 PostgreSQL 数据库中。
要运行挂起的迁移,您将 exec
进入正在运行的应用程序 pod,然后调用 rake db:migrate
命令。
首先,使用以下命令找到应用程序 pod 的名称:
kubectl get pods
找到与您的应用程序对应的 pod,如以下输出中突出显示的 pod 名称:
OutputNAME READY STATUS RESTARTS AGE app-854d645fb9-9hv7w 1/1 Running 0 30s database-c77d55fbb-bmfm8 1/1 Running 0 30s redis-7d65467b4d-9hcxk 1/1 Running 0 30s sidekiq-867f6c9c57-mcwks 1/1 Running 0 30s
记下该 pod 名称后,您现在可以运行 kubectl exec
命令来完成数据库迁移步骤。
使用以下命令运行迁移:
kubectl exec your_app_pod_name -- rake db:migrate
您应该会收到类似于以下内容的输出,这表明已加载数据库架构:
Output== 20190927142853 CreateSharks: migrating ===================================== -- create_table(:sharks) -> 0.0190s == 20190927142853 CreateSharks: migrated (0.0208s) ============================ == 20190927143639 CreatePosts: migrating ====================================== -- create_table(:posts) -> 0.0398s == 20190927143639 CreatePosts: migrated (0.0421s) ============================= == 20191120132043 CreateEndangereds: migrating ================================ -- create_table(:endangereds) -> 0.8359s == 20191120132043 CreateEndangereds: migrated (0.8367s) =======================
随着您的容器运行并加载数据,您现在可以访问该应用程序。 要获取 app
LoadBalancer 的 IP,请键入:
kubectl get svc
您将收到如下输出:
OutputNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE app LoadBalancer 10.245.73.142 your_lb_ip 3000:31186/TCP 21m database ClusterIP 10.245.155.87 <none> 5432/TCP 21m kubernetes ClusterIP 10.245.0.1 <none> 443/TCP 21m redis ClusterIP 10.245.119.67 <none> 6379/TCP 21m
与 app
服务关联的 EXTERNAL_IP
是您可以访问应用程序的 IP 地址。 如果您在 EXTERNAL_IP
列中看到 <pending>
状态,这意味着您的负载均衡器仍在创建中。
在该列中看到 IP 后,在浏览器中导航到它:http://your_lb_ip:3000
。
您应该看到以下登录页面:
单击获取鲨鱼信息按钮。 您将有一个带有按钮的页面来创建新鲨鱼:
单击它,并在出现提示时输入本教程系列前面的用户名和密码。 如果您没有更改这些值,则默认值分别为 sammy
和 shark
。
在表格中,添加您选择的鲨鱼。 为了演示,我们将 Megalodon Shark
添加到 Shark Name 字段,并将 Ancient
添加到 Shark Character 字段:
单击提交按钮。 您将看到一个页面,其中向您显示此鲨鱼信息:
您现在拥有一个 Rails 应用程序的单实例设置,其中包含在 Kubernetes 集群上运行的 PostgreSQL 数据库。 您还有一个 Redis 缓存和一个 Sidekiq 工作器来处理用户提交的数据。
结论
您在本教程中创建的文件是您在进入生产阶段时构建的良好起点。 在开发应用程序时,您可以着手实现以下内容:
- 集中记录和监控。 请参阅 Kubernetes 的现代化应用程序 中的 相关讨论 以获得一般概述。 您还可以查看 如何在 Kubernetes 上设置 Elasticsearch、Fluentd 和 Kibana (EFK) 日志记录堆栈 以了解如何使用 Elasticsearch、Fluentd 设置日志记录堆栈 和 Kibana。 另请查看 An Introduction to Service Meshes 以了解有关 Istio 等服务网格如何实现此功能的信息。
- 将流量路由到集群的入口资源。 如果您正在运行多个服务,每个服务都需要自己的 LoadBalancer,或者您希望实现应用程序级路由策略(例如 A/B 和金丝雀测试),这是 LoadBalancer 的一个很好的替代方案。 更多信息请查看How to Set Up an Nginx Ingress with Cert-Manager on DigitalOcean Kubernetes和An Introduction to Service Mesh context中路由的相关讨论服务网格。
- Kubernetes 对象的备份策略。 有关使用 DigitalOcean 的 Kubernetes 产品使用 Velero 实施备份的指南,请参阅 如何使用 Velero 在 DigitalOcean 上备份和恢复 Kubernetes 集群。