亚马逊AWS官方博客

在 Kubernetes 中为应用程序部署 Amazon RDS 数据库

Kubernetes 容器编排系统为管理分布式环境中的应用程序提供了大量资源。其中许多应用程序都需要一个安全、持久和高性能的可搜索存储系统来存储其数据。开发人员希望专注于不断改进其应用程序,而不必担心其数据库的运行功能。他们还需要一种直接从 Kubernetes 连接和管理数据库的方法。通过将  Amazon Elastic Kubernetes Service(Amazon EKS)和  Amazon Relational Database Service(Amazon RDS)相结合,您可以获得灵活的应用程序部署环境,轻松进行数据库管理。Amazon EKS 提供强大的托管 Kubernetes 服务,用于在应用程序生命周期的所有阶段(开发、QA/UAT、暂存、生产)部署应用程序。同时,Amazon RDS 使开发人员可为应用程序选择自己喜欢的数据库引擎( Amazon AuroraAmazon RDS for PostgreSQLAmazon RDS for MySQLAmazon RDS for MariaDBAmazon RDS for OracleAmazon RDS for SQL Server),具有基本的生产功能,例如安全性、高可用性、自动备份、增强的监控和高性能存储。 适用于 Kubernetes 的 AWS 控制器(ACK)提供了一个界面,让您可以直接从 Kubernetes 使用其他 AWS 服务。要通过 Kubernetes 管理 Amazon RDS 数据库实例,我们可以使用 ACK。借助适用于 Amazon RDS 的 ACK 服务控制器,您可以使用 kubectl 和 自定义资源 预置和管理数据库实例!在这篇文章中,我们将引导您完成将项目管理工具  Jira 部署到 Amazon EKS 提供的 Kubernetes 集群中。我们使用 Amazon RDS for PostgreSQL 作为 Jira 的数据库系统。

先决条件

我们需要一些工具来设置生产就绪型 Jira 部署。确保您的工作环境中有以下每种工具:

您必须拥有适当的 AWS Identity and Access Management(IAM)权限才能与不同的 AWS 服务进行交互。有关更多信息,请参阅以下内容:

这篇文章使用 shell 变量,让替换部署的实际名称变得更容易。当您看到像 NAME=<your xyz name> 这样的占位符时,请使用您的环境的名称来替换。

当安装到 Kubernetes 集群中时,Jira 需要 Kubernetes 1.19 或更高版本。在本文写作之时,Jira 仅经过验证可在 PostgreSQL 13 及之前版本中工作

设置 Amazon EKS 集群

首先,我们需要设置我们的 Amazon EKS 集群。使用 eksctl 创建 Amazon EKS 集群并确保已启用 IAM OIDC 提供程序

EKS_CLUSTER_NAME="<your cluster name>"
REGION="<your region>"

eksctl create cluster \
  --name "${EKS_CLUSTER_NAME}" \
  --region "${REGION}" \
  --with-oidc \
  --instance-selector-vcpus 4 \
  --instance-selector-memory "8Gi"

我们希望确保有足够的资源来运行 Jira 应用程序,因此我们要求节点上有 4 个 vCPU 和 8 GiB 的 RAM。预置 Amazon EKS 集群可能需要 15-30 分钟。当您的集群准备就绪时,尝试通过运行 kubectl get 节点来访问它:

$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-192-168-0-58.us-east-2.compute.internal Ready <none> 2m17s v1.21.5-eks-9017834
ip-192-168-33-177.us-east-2.compute.internal Ready <none> 2m16s v1.21.5-eks-9017834

使用 Amazon EFS CSI 驱动程序设置共享存储

集群模式下运行时(这是生产部署的典型情况),Jira 需要使用共享文件系统。Amazon EKS 提供了 Amazon EFS CSI 驱动程序,以便为一组容器(pod)提供共享文件存储系统。有关如何将 Amazon Elastic File System(Amazon EFS)系统连接到 Kubernetes 集群的说明,请参阅 Amazon EFS CSI 驱动程序

Amazon EFS 安装指南使用名为 efs-sc 的 Kubernetes 存储类。它用于动态预置 Amazon EFS 存储。我们稍后将在此示例中引用 efs-sc 存储类。

允许使用 AWS 负载均衡器控制器进行外部 Web 访问

我们还需要一种在外部访问 Jira 应用程序的方法。我们可以使用 AWS 负载均衡器控制器来完成此操作。有关安装说明,请参阅负载均衡器控制器安装

安装适用于 Amazon RDS 的 ACK 服务控制器

适用于 Amazon RDS 的 ACK 服务控制器使我们可以直接从 Kubernetes 管理我们的 Amazon RDS for PostgreSQL 实例。有关安装说明,请参阅安装适用于 Amazon RDS 的 ACK 服务控制器

为 Jira 创建命名空间

我们将我们的 Jira 应用程序和任何关联的对象放入他们自己的 Kubernetes 命名空间。为简单起见,我们将我们的命名空间命名为 jira

APP_NAMESPACE=jira
kubectl create ns "${APP_NAMESPACE}"

为方便起见,我们还在 jira 命名空间中管理我们的 Amazon RDS 自定义资源。

设置数据库联网

让我们将 VPC 子网关联到数据库子网组。这是一个构建块,使我们的 Pod 可以安全地访问在此 Amazon EKS 集群中预置的任何 Amazon RDS 数据库。这也是我们如何使用适用于 Amazon RDS 的 ACK 服务控制器从 Amazon EKS 直接与 Amazon RDS 进行交互的第一个示例。

以下代码段找出 Amazon EKS 集群正在使用的子网。然后,它将为 DBSubnetGroup 自定义资源生成一个 Kubernetes 清单,其中包含要添加到数据库子网组的子网列表:

RDS_SUBNET_GROUP_NAME="<your subnet group name>"
RDS_SUBNET_GROUP_DESCRIPTION="<your subnet group description>"
EKS_SUBNET_IDS=$(aws ec2 describe-subnets \
  --filters "Name=vpc-id,Values=${EKS_VPC_ID}" \
  --query 'Subnets[*].SubnetId' \
  --output text
)

cat <<-EOF > db-subnet-groups.yaml
apiVersion: rds.services.k8s.aws/v1alpha1
kind: DBSubnetGroup
metadata:
  name: ${RDS_SUBNET_GROUP_NAME}
  namespace: ${APP_NAMESPACE}
spec:
  name: ${RDS_SUBNET_GROUP_NAME}
  description: ${RDS_SUBNET_GROUP_DESCRIPTION}
  subnetIDs:
$(printf "    - %s\n" ${EKS_SUBNET_IDS})
  tags: []
EOF

kubectl apply -f db-subnet-groups.yaml

应用之后,Kubernetes 会在 jira 命名空间中创建这个 DBSubnetGroup 自定义资源。适用于 Amazon RDS 的 ACK 服务控制器会检测新的 DBSubnetGroup 资源,然后与 Amazon RDS API 连接以创建子网组。

我们现在需要创建安全组,以允许此 Amazon EKS 集群中的 Pod 访问您预置的 Amazon RDS 数据库。您可以使用以下命令执行此操作:

RDS_SECURITY_GROUP_NAME="<your security group name>"
RDS_SECURITY_GROUP_DESCRIPTION="<your security group description>"

EKS_CIDR_RANGE=$(aws ec2 describe-vpcs \
  --vpc-ids $EKS_VPC_ID \
  --query "Vpcs[].CidrBlock" \
  --output text
)

RDS_SECURITY_GROUP_ID=$(aws ec2 create-security-group \
  --group-name "${RDS_SUBNET_GROUP_NAME}" \
  --description "${RDS_SUBNET_GROUP_DESCRIPTION}" \
  --vpc-id "${EKS_VPC_ID}" \
  --output text
)

aws ec2 authorize-security-group-ingress \
  --group-id "${RDS_SECURITY_GROUP_ID}" \
  --protocol tcp \
  --port 5432 \
  --cidr "${EKS_CIDR_RANGE}"

这里有很多代码,但现在我们已经准备好部署我们的生产应用程序了。

预置 Amazon RDS for PostgreSQL 数据库实例

在部署 Jira 之前,我们设置了 Amazon RDS for PostgreSQL 数据库实例。

借助适用于 Amazon RDS 的 ACK 服务控制器,我们可以使用 Kubernetes API 预置 Amazon RDS for PostgreSQL 数据库实例。我们可以通过创建一个 DBInstance 自定义资源来做到这一点。DBInstance 自定义资源定义遵循 Amazon RDS API,因此您也可以在构建自定义资源时将其用作参考。

在创建 DBInstance 自定义资源之前,我们必须先创建一个包含主数据库用户名和密码的 Kubernetes 密钥DBInstance 和 Jira 安装程序都需要使用这个密钥。提供所需的用户名和密码,然后创建该密钥:

RDS_DB_USERNAME="<your username>"
RDS_DB_PASSWORD="<your secure password>"

kubectl create secret generic -n "${APP_NAMESPACE}" jira-postgres-creds \
  --from-literal=username="${RDS_DB_USERNAME}" \
  --from-literal=password="${RDS_DB_PASSWORD}"

创建密钥后,从环境中清除密码:

unset RDS_DB_PASSWORD

现在我们可以创建 Amazon RDS 数据库实例了! 以下清单预置了高可用性 Amazon RDS for PostgreSQL 多可用区数据库,该数据库具有备份、增强监控和加密存储:

RDS_DB_INSTANCE_NAME="jira-db"
RDS_DB_INSTANCE_CLASS="db.m6g.large"
RDS_DB_STORAGE_SIZE=100

cat <<-EOF > jira-db.yaml 
apiVersion: rds.services.k8s.aws/v1alpha1
kind: DBInstance
metadata:
  name: ${RDS_DB_INSTANCE_NAME}
  namespace: ${APP_NAMESPACE}
spec:
  allocatedStorage: ${RDS_DB_STORAGE_SIZE}
  autoMinorVersionUpgrade: true
  backupRetentionPeriod: 7
  dbInstanceClass: ${RDS_DB_INSTANCE_CLASS}
  dbInstanceIdentifier: ${RDS_DB_INSTANCE_NAME}
  dbName: jira
  dbSubnetGroupName: ${RDS_SUBNET_GROUP_NAME}
  enablePerformanceInsights: true
  engine: postgres
  engineVersion: "13"
  masterUsername: ${RDS_DB_USERNAME}
  masterUserPassword:
    namespace: ${APP_NAMESPACE}
    name: jira-postgres-creds
    key: password
  multiAZ: true
  publiclyAccessible: false
  storageEncrypted: true
  storageType: gp2
  vpcSecurityGroupIDs:
    - ${RDS_SECURITY_GROUP_ID}
EOF

kubectl apply -f jira-db.yaml

您可以使用 kubectl describe dbinstance 查看 Amazon RDS for PostgreSQL 实例的详细信息;例如:

kubectl describe dbinstance -n "${APP_NAMESPACE}" "${RDS_DB_INSTANCE_NAME}

Amazon RDS for PostgreSQL 实例可能需要 5-10 分钟才能准备就绪。要检查其可用性,可以使用以下命令:

kubectl get dbinstance -n "${APP_NAMESPACE}" "${RDS_DB_INSTANCE_NAME}" \
    -o jsonpath='{.status.dbInstanceStatus}'

DBInstance 自定义资源在 status 部分包含有关 Amazon RDS for PostgreSQL 实例的当前状态和其他属性的详细信息。您可以使用 kubectl describe dbinstance 来查看此信息;例如:

kubectl describe dbinstance -n "${APP_NAMESPACE}" "${RDS_DB_INSTANCE_NAME}"

有关更多信息,请参阅适用于 Amazon RDS 的 ACK 服务控制器的状态文档

当您的 Amazon RDS for PostgreSQL 实例可用时,请存储 PostgreSQL 端点和端口的值。我们需要他们来连接 Jira。

RDS_DB_INSTANCE_HOST=$(kubectl get dbinstance -n "${APP_NAMESPACE}" "${RDS_DB_INSTANCE_NAME}" \
  -o jsonpath='{.status.endpoint.address}'
)
RDS_DB_INSTANCE_PORT=$(kubectl get dbinstance -n "${APP_NAMESPACE}" "${RDS_DB_INSTANCE_NAME}" \
  -o jsonpath='{.status.endpoint.port}'
)

现在,您的 Amazon RDS for PostgreSQL 实例已正常运行,并已为生产工作负载做好准备,我们可以连接 Jira 了!

将 Jira 部署到 Amazon EKS

要在我们的 Amazon EKS 环境中安装 Jira,我们首先需要下载 Jira Helm Chart。您可以使用以下命令执行此操作:

helm repo add atlassian-data-center \
  https://atlassian.github.io/data-center-helm-charts
helm repo update

Jira 安装说明提供了有关如何配置 Helm values.yaml 文件的详细信息。为了利用我们之前设置的环境变量,我们使用以下命令生成 values.yaml 文件:

JIRA_VERSION="1.1.0"

cat <<-EOF > jira.yaml
# Jira 文档指出,在从浏览器进行初始配置后,将 replicaCount
# 设置为更大的数字
replicaCount: 1
image:
  repository: atlassian/jira-software
  pullPolicy: IfNotPresent
serviceAccount:
  create: true
database:
  type: postgres72
  url: jdbc:postgresql://${RDS_DB_INSTANCE_HOST}:${RDS_DB_INSTANCE_PORT}/jira
  driver: org.postgresql.Driver
  credentials:
    secretName: jira-postgres-creds
    usernameSecretKey: username
    passwordSecretKey: password
volumes:
  localHome:
    persistentVolumeClaim:
      create: true
      storageClassName: gp2
      resources:
        requests:
          storage: 1Gi
    customVolume: {}
    mountPath: "/var/atlassian/application-data/jira"
  sharedHome:
    persistentVolumeClaim:
      create: true
      storageClassName: efs-sc
      resources:
        requests:
          storage: 1Gi
    customVolume: {}
    mountPath: "/var/atlassian/application-data/shared-home"
    nfsPermissionFixer:
      enabled: true
      mountPath: "/shared-home"
      command:
  additional: []
ingress:
  create: true
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
jira:
  service:
    port: 80
    type: ClusterIP
    contextPath:
    annotations: {}
  securityContext:
    fsGroup: 2001
  containerSecurityContext: {}
  setPermissions: true
  ports:
    http: 8080
    ehcache: 40001
    ehcacheobject: 40011
  readinessProbe:
    initialDelaySeconds: 10
    periodSeconds: 5
    failureThreshold: 30
  accessLog:
    mountPath: "/opt/atlassian/jira/logs"
    localHomeSubPath: "log"
  clustering:
    enabled: true
  license:
    secretName:
    secretKey: license-key
  shutdown:
    terminationGracePeriodSeconds: 30
    command: "/shutdown-wait.sh"
  resources:
    jvm:
      maxHeap: "768m"
      minHeap: "384m"
      reservedCodeCache: "512m"
    container:
      requests:
        cpu: "2" # If changing the cpu value update 'ActiveProcessorCount' below
        memory: "2G"
  additionalJvmArgs:
    - -XX:ActiveProcessorCount=2
  additionalLibraries: []
  additionalBundledPlugins: []
  additionalVolumeMounts: []
  additionalEnvironmentVariables: []
fluentd:
  enabled: false
podAnnotations: {}
nodeSelector: {}
tolerations: []
affinity: {}
schedulerName:
additionalContainers: []
additionalInitContainers: []
additionalLabels: {}
additionalFiles: []
EOF

helm install jira atlassian-data-center/jira -n "${APP_NAMESPACE}" \
  --version="${JIRA_VERSION}" --values=jira.yaml

此示例使用 AWS 负载均衡器控制器创建一个入口,以提供对 Jira 实例的公有访问权限。默认情况下,在没有 TLS 端点的情况下创建入口。有关更多信息,请参阅使用新的 AWS 负载均衡器控制器在 Amazon EKS 中设置端到端 TLS 加密。根据您的安全要求,您可能不想提供公有访问权限。如果是这种情况,请不要创建入口。

Jira 可能需要 2-5 分钟才能初始化。您可以使用以下命令获取在 Web 浏览器中访问 Jira 的端点的名称:

kubectl get ingress -n "${APP_NAMESPACE}" jira \
  -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'

复制此值并在 Web 浏览器中导航到此端点。现在,您应该会看到 Jira 初始设置页面。

Jira 设置屏幕

恭喜,您现在已经在 Amazon EKS 中直接部署了 Jira 及其 Amazon RDS for PostgreSQL 多可用区实例!

清理

如果您想删除 Jira 实例和 AWS 负载均衡器实例,可以使用 helm 来完成:

helm delete jira -n "${APP_NAMESPACE}"

不会删除不是由 Jira Helm Chart 创建的构件。您可以使用以下命令删除数据库实例:

kubectl delete -f jira-db.yaml

您还必须删除包含 Amazon RDS for PostgreSQL 用户凭证的 Kubernetes 密钥。您可以使用以下命令删除此密钥:

kubectl delete secret -n "${APP_NAMESPACE}" jira-postgresc-reds

要删除数据库子网组,请使用以下命令:

kubectl delete -f db-subnet-groups.yaml

要卸载适用于 Amazon ADS 的 ACK 服务控制器,请参阅卸载 ACK 控制器。按照该示例,将 SERVICE 的值设置为 rds。

您可以使用以下命令删除 AWS 负载均衡器控制器:

helm delete aws-load-balancer-controller -n kube-system

您可以使用以下命令删除 efs-sc 存储类和 Amazon EFS CSI 驱动程序:

kubectl delete storageclass efs-sc
helm delete aws-efs-csi-driver -n kube-system

要删除 Amazon EKS 集群,请参阅删除 Amazon EKS 集群

eksctl delete cluster \
  --name "${EKS_CLUSTER_NAME}" \
  --region "${REGION}"

结论

我们看到了适用于 Kubernetes 的 AWS 控制器如何让您直接从 Amazon EKS 环境部署 Amazon RDS for PostgreSQL 实例并将应用程序连接到该实例。您可以将此示例用于其他 Amazon RDS 数据库引擎,JIRA 支持具有 PostgreSQL 兼容性的 Amazon Aurora、Amazon RDS for MySQL、Amazon RDS for Oracle 和 Amazon RDS for SQL Server。有关更多信息,请参阅支持的平台

这篇文章只展示了如何使用 ACK 服务控制器直接从 Kubernetes 与 Amazon RDS 等 AWS 服务进行交互的一个示例。我们还可以使用 ACK Amazon EC2 控制器构建此示例。

适用于 Kubernetes 的 AWS 控制器提供了一种便捷方式,可以直接从 Kubernetes 将您的 Kubernetes 应用程序连接到 AWS 服务。告诉我们您的体验! ACK 是开源的:您可以在 ACK 社区 GitHub 存储库请求新功能和报告问题,或者在本文的评论部分添加评论。

本篇作者

Jonathan Katz

Jonathan Katz 是 Amazon RDS 团队的首席 PMT,常驻纽约。他是开源 PostgreSQL 项目的核心团队成员,并且是活跃的开源贡献者。