如何将用于Rails开发的DockerCompose工作流迁移到Kubernetes

来自菜鸟教程
跳转至:导航、​搜索

介绍

在构建现代的无状态应用程序时, 将应用程序的组件容器化 是在分布式平台上部署和扩展的第一步。 如果您在开发中使用了 Docker Compose,您将通过以下方式对您的应用程序进行现代化和容器化:

  • 从代码中提取必要的配置信息。
  • 卸载应用程序的状态。
  • 打包您的应用程序以供重复使用。

您还将编写指定容器映像应如何运行的服务定义。

要在 Kubernetes 等分布式平台上运行您的服务,您需要将 Compose 服务定义转换为 Kubernetes 对象。 这将允许您 以弹性 扩展您的应用程序。 kompose 是一种可以加快向 Kubernetes 的转换过程的工具,它是一种转换工具,可帮助开发人员将 Compose 工作流迁移到 Kubernetes 或 OpenShift 等容器编排器。

在本教程中,您将使用 kompose 将 Compose 服务转换为 Kubernetes objects。 您将使用 kompose 提供的对象定义作为起点并进行调整,以确保您的设置将使用 SecretsServicesPersistentVolumeClaims 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 服务定义中包含对我们新建应用程序映像的引用,并删除 绑定 mountsvolumes 和其他 命令[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_USERPOSTGRES_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_cachenode_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 ComposeStep 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_NAMEDATABASE_USERDATABASE_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_DBPOSTGRES_USERPOSTGRES_PASSWORDpostgres 图像使这些变量可用,以便您可以修改数据库实例的初始化。 POSTGRES_DB 创建容器启动时可用的默认数据库。 POSTGRES_USERPOSTGRES_PASSWORD 共同创建一个可以访问创建的数据库的特权用户。

使用这些值意味着我们创建的用户可以访问该角色在 PostgreSQL 中的所有管理和操作权限。 在生产中工作时,您需要创建一个具有适当范围权限的专用应用程序用户。

POSTGRES_DBPOSTGRES_USERPOSTGRES_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: {}

另请注意 accessModeReadWriteOnce 表示由于此声明而配置的卷将只能由单个节点读写。 有关不同访问模式的更多信息,请参阅 文档

完成后保存并关闭文件。

接下来,打开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 容器正在启动时,您将看到类似于以下的输出(状态将为 PendingContainerCreating):

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

您应该看到以下登录页面:

单击获取鲨鱼信息按钮。 您将有一个带有按钮的页面来创建新鲨鱼:

单击它,并在出现提示时输入本教程系列前面的用户名和密码。 如果您没有更改这些值,则默认值分别为 sammyshark

在表格中,添加您选择的鲨鱼。 为了演示,我们将 Megalodon Shark 添加到 Shark Name 字段,并将 Ancient 添加到 Shark Character 字段:

单击提交按钮。 您将看到一个页面,其中向您显示此鲨鱼信息:

您现在拥有一个 Rails 应用程序的单实例设置,其中包含在 Kubernetes 集群上运行的 PostgreSQL 数据库。 您还有一个 Redis 缓存和一个 Sidekiq 工作器来处理用户提交的数据。

结论

您在本教程中创建的文件是您在进入生产阶段时构建的良好起点。 在开发应用程序时,您可以着手实现以下内容: