11.12. 将日志转发到 Amazon CloudWatch

您可以将日志转发到 Amazon CloudWatch,这是由 Amazon Web Services (AWS) 托管的监控和日志存储服务。除了默认的日志存储外,您还可以将日志转发到 CloudWatch。

要配置日志转发到 CloudWatch,您必须创建一个 ClusterLogForwarder 自定义资源 (CR),其中包含 CloudWatch 的输出,以及使用输出的管道。

流程

  1. 创建一个 Secret YAML 文件,它使用 aws_access_key_idaws_secret_access_key 字段来指定您的 base64 编码的 AWS 凭证。例如:

    apiVersion: v1
    kind: Secret
    metadata:
      name: cw-secret
      namespace: openshift-logging
    data:
      aws_access_key_id: QUtJQUlPU0ZPRE5ON0VYQU1QTEUK
      aws_secret_access_key: d0phbHJYVXRuRkVNSS9LN01ERU5HL2JQeFJmaUNZRVhBTVBMRUtFWQo=
  2. 创建 secret.例如:

    $ oc apply -f cw-secret.yaml
  3. 创建或编辑定义 ClusterLogForwarder CR 对象的 YAML 文件。在文件中,指定 secret 的名称。例如:

    apiVersion: "logging.openshift.io/v1"
    kind: ClusterLogForwarder
    metadata:
      name: instance 1
      namespace: openshift-logging 2
    spec:
      outputs:
       - name: cw 3
         type: cloudwatch 4
         cloudwatch:
           groupBy: logType 5
           groupPrefix: <group prefix> 6
           region: us-east-2 7
         secret:
            name: cw-secret 8
      pipelines:
        - name: infra-logs 9
          inputRefs: 10
            - infrastructure
            - audit
            - application
          outputRefs:
            - cw 11
    1
    ClusterLogForwarder CR 的名称必须是 instance
    2
    ClusterLogForwarder CR 的命名空间必须是 openshift-logging
    3
    指定输出的名称。
    4
    指定 cloudwatch 类型。
    5
    可选:指定如何对日志进行分组:
    • logType 为每个日志类型创建日志组
    • namespaceName 为每个应用程序命名空间创建一个日志组。它还会为基础架构和审计日志创建单独的日志组。
    • namespaceUUID 为每个应用命名空间 UUID 创建一个新的日志组。它还会为基础架构和审计日志创建单独的日志组。
    6
    可选:指定一个字符串来替换日志组名称中的默认 infrastructureName 前缀。
    7
    指定 AWS 区域。
    8
    指定包含 AWS 凭证的 secret 名称。
    9
    可选:指定管道的名称。
    10
    使用管道指定要转发的日志类型:applicationinfrastructureaudit
    11
    指定使用此管道转发日志时使用的输出名称。
  4. 创建 CR 对象。

    $ oc create -f <file-name>.yaml

示例:在 Amazon CloudWatch 中使用 ClusterLogForwarder

在这里,您会看到 ClusterLogForwarder 自定义资源 (CR) 示例及其输出到 Amazon CloudWatch 的日志数据。

假设您正在运行名为 mycluster 的 OpenShift Container Platform 集群。以下命令返回集群的 infrastructureName,稍后您将用它来编写 aws 命令:

$ oc get Infrastructure/cluster -ojson | jq .status.infrastructureName
"mycluster-7977k"

要为本例生成日志数据,您可以在名为 app 的命名空间中运行 busybox pod。busybox pod 每隔三秒钟将消息写入 stdout:

$ oc run busybox --image=busybox -- sh -c 'while true; do echo "My life is my message"; sleep 3; done'
$ oc logs -f busybox
My life is my message
My life is my message
My life is my message
...

您可以查找 busybox pod 运行的 app 命名空间的 UUID:

$ oc get ns/app -ojson | jq .metadata.uid
"794e1e1a-b9f5-4958-a190-e76a9b53d7bf"

ClusterLogForwarder 自定义资源 (CR) 中,您可以将 infrastructureauditapplication 日志类型配置为 all-logs 管道的输入。您还可以将此管道连接到 cw 输出,输出将日志转发到 us-east-2 区域的 CloudWatch 实例:

apiVersion: "logging.openshift.io/v1"
kind: ClusterLogForwarder
metadata:
  name: instance
  namespace: openshift-logging
spec:
  outputs:
   - name: cw
     type: cloudwatch
     cloudwatch:
       groupBy: logType
       region: us-east-2
     secret:
        name: cw-secret
  pipelines:
    - name: all-logs
      inputRefs:
        - infrastructure
        - audit
        - application
      outputRefs:
        - cw

CloudWatch 中的每个地区都包含三个级别的对象:

  • 日志组

    • 日志流

      • 日志事件

使用 ClusterLogForwarding CR 中的 groupBy: logTypeinputRefs 中的三种日志类型会在 Amazon Cloudwatch 中生成三个日志组:

$ aws --output json logs describe-log-groups | jq .logGroups[].logGroupName
"mycluster-7977k.application"
"mycluster-7977k.audit"
"mycluster-7977k.infrastructure"

每个日志组都包含日志流:

$ aws --output json logs describe-log-streams --log-group-name mycluster-7977k.application | jq .logStreams[].logStreamName
"kubernetes.var.log.containers.busybox_app_busybox-da085893053e20beddd6747acdbaf98e77c37718f85a7f6a4facf09ca195ad76.log"
$ aws --output json logs describe-log-streams --log-group-name mycluster-7977k.audit | jq .logStreams[].logStreamName
"ip-10-0-131-228.us-east-2.compute.internal.k8s-audit.log"
"ip-10-0-131-228.us-east-2.compute.internal.linux-audit.log"
"ip-10-0-131-228.us-east-2.compute.internal.openshift-audit.log"
...
$ aws --output json logs describe-log-streams --log-group-name mycluster-7977k.infrastructure | jq .logStreams[].logStreamName
"ip-10-0-131-228.us-east-2.compute.internal.kubernetes.var.log.containers.apiserver-69f9fd9b58-zqzw5_openshift-oauth-apiserver_oauth-apiserver-453c5c4ee026fe20a6139ba6b1cdd1bed25989c905bf5ac5ca211b7cbb5c3d7b.log"
"ip-10-0-131-228.us-east-2.compute.internal.kubernetes.var.log.containers.apiserver-797774f7c5-lftrx_openshift-apiserver_openshift-apiserver-ce51532df7d4e4d5f21c4f4be05f6575b93196336be0027067fd7d93d70f66a4.log"
"ip-10-0-131-228.us-east-2.compute.internal.kubernetes.var.log.containers.apiserver-797774f7c5-lftrx_openshift-apiserver_openshift-apiserver-check-endpoints-82a9096b5931b5c3b1d6dc4b66113252da4a6472c9fff48623baee761911a9ef.log"
...

每个日志流都包含日志事件。要查看 busybox Pod 的日志事件,您可以从 application 日志组中指定其日志流:

$ aws logs get-log-events --log-group-name mycluster-7977k.application --log-stream-name kubernetes.var.log.containers.busybox_app_busybox-da085893053e20beddd6747acdbaf98e77c37718f85a7f6a4facf09ca195ad76.log
{
    "events": [
        {
            "timestamp": 1629422704178,
            "message": "{\"docker\":{\"container_id\":\"da085893053e20beddd6747acdbaf98e77c37718f85a7f6a4facf09ca195ad76\"},\"kubernetes\":{\"container_name\":\"busybox\",\"namespace_name\":\"app\",\"pod_name\":\"busybox\",\"container_image\":\"docker.io/library/busybox:latest\",\"container_image_id\":\"docker.io/library/busybox@sha256:0f354ec1728d9ff32edcd7d1b8bbdfc798277ad36120dc3dc683be44524c8b60\",\"pod_id\":\"870be234-90a3-4258-b73f-4f4d6e2777c7\",\"host\":\"ip-10-0-216-3.us-east-2.compute.internal\",\"labels\":{\"run\":\"busybox\"},\"master_url\":\"https://kubernetes.default.svc\",\"namespace_id\":\"794e1e1a-b9f5-4958-a190-e76a9b53d7bf\",\"namespace_labels\":{\"kubernetes_io/metadata_name\":\"app\"}},\"message\":\"My life is my message\",\"level\":\"unknown\",\"hostname\":\"ip-10-0-216-3.us-east-2.compute.internal\",\"pipeline_metadata\":{\"collector\":{\"ipaddr4\":\"10.0.216.3\",\"inputname\":\"fluent-plugin-systemd\",\"name\":\"fluentd\",\"received_at\":\"2021-08-20T01:25:08.085760+00:00\",\"version\":\"1.7.4 1.6.0\"}},\"@timestamp\":\"2021-08-20T01:25:04.178986+00:00\",\"viaq_index_name\":\"app-write\",\"viaq_msg_id\":\"NWRjZmUyMWQtZjgzNC00MjI4LTk3MjMtNTk3NmY3ZjU4NDk1\",\"log_type\":\"application\",\"time\":\"2021-08-20T01:25:04+00:00\"}",
            "ingestionTime": 1629422744016
        },
...

示例:在日志组群名称中自定义前缀

在日志组名称中,您可以将默认的 infrastructureName 前缀 mycluster-7977k 替换为一个任意字符串,如 demo-group-prefix。要进行此更改,您需要更新 ClusterLogForwarding CR 中的 groupPrefix 字段:

cloudwatch:
    groupBy: logType
    groupPrefix: demo-group-prefix
    region: us-east-2

groupPrefix 的值替换默认的 infrastructureName 前缀:

$ aws --output json logs describe-log-groups | jq .logGroups[].logGroupName
"demo-group-prefix.application"
"demo-group-prefix.audit"
"demo-group-prefix.infrastructure"

示例:应用程序命名空间名称后命名日志组

对于集群中的每个应用程序命名空间,您可以在 CloudWatch 中创建日志组,其名称基于应用程序命名空间的名称。

如果您删除应用程序命名空间对象并创建名称相同的新对象,CloudWatch 会继续使用与以前相同的日志组。

如果您认为名称相同的连续应用程序命名空间对象相互等效,请使用本例中描述的方法。否则,如果您需要将生成的日志组相互区分,请参阅以下"为应用命名空间 UUID 注入日志组"部分。

要创建名称基于应用程序命名空间名称的应用程序日志组,您可以在 ClusterLogForwarder CR 中将 groupBy 字段的值设置为 namespaceName

cloudwatch:
    groupBy: namespaceName
    region: us-east-2

groupBy 设置为 namespaceName 只会影响应用程序日志组。它不会影响 auditinfrastructure 日志组。

在 Amazon Cloudwatch 中,命名空间名称显示在每个日志组名称的末尾。因为只有一个应用程序命名空间 "app",以下输出显示一个新的 mycluster-7977k.app 日志组,而不是 mycluster-7977k.application

$ aws --output json logs describe-log-groups | jq .logGroups[].logGroupName
"mycluster-7977k.app"
"mycluster-7977k.audit"
"mycluster-7977k.infrastructure"

如果本例中的集群包含多个应用命名空间,则输出中会显示多个日志组,每个命名空间对应一个日志组。

groupBy 字段仅影响应用日志组。它不会影响 auditinfrastructure 日志组。

示例:应用程序命名空间 UUID 后命名日志组

对于集群中的每个应用程序命名空间,您可以在 CloudWatch 中创建日志组,其名称是基于应用程序命名空间的 UUID。

如果您删除应用程序命名空间对象并创建新对象,CloudWatch 会创建一个新的日志组。

如果您考虑使用名称相同的连续应用程序命名空间对象,请使用本例中描述的方法。否则,请参阅前面的 "Example: Naming log groups for application namespace name" 部分。

要在应用程序命名空间 UUID 后命名日志组,您可以在 ClusterLogForwarder CR 中将 groupBy 字段的值设置为 namespaceUUID

cloudwatch:
    groupBy: namespaceUUID
    region: us-east-2

在 Amazon Cloudwatch 中,命名空间 UUID 出现在每个日志组名称的末尾。因为有一个应用程序命名空间 "app",以下输出显示一个新的 mycluster-7977k.794e1e1a-b9f5-4958-a190-e76a9b53d7bf 日志组,而不是 mycluster-7977k.application

$ aws --output json logs describe-log-groups | jq .logGroups[].logGroupName
"mycluster-7977k.794e1e1a-b9f5-4958-a190-e76a9b53d7bf" // uid of the "app" namespace
"mycluster-7977k.audit"
"mycluster-7977k.infrastructure"

groupBy 字段仅影响应用日志组。它不会影响 auditinfrastructure 日志组。

11.12.1. 从启用了 STS 的集群将日志转发到 Amazon CloudWatch

对于启用了 AWS Security Token Service (STS) 的集群,您可以手动创建 AWS 服务帐户,或使用 Cloud Credential Operator (CCO) 实用程序 ccoctl 创建凭证请求。

注意

vector 收集器不支持此功能。

先决条件

  • Red Hat OpenShift 的日志记录子系统: 5.5 及更新的版本

流程

  1. 使用以下模板创建 CredentialsRequest 自定义资源 YAML:

    Cloudwatch 凭证请求模板

    apiVersion: cloudcredential.openshift.io/v1
    kind: CredentialsRequest
    metadata:
      name: <your_role_name>-credrequest
      namespace: openshift-cloud-credential-operator
    spec:
      providerSpec:
        apiVersion: cloudcredential.openshift.io/v1
        kind: AWSProviderSpec
        statementEntries:
          - action:
              - logs:PutLogEvents
              - logs:CreateLogGroup
              - logs:PutRetentionPolicy
              - logs:CreateLogStream
              - logs:DescribeLogGroups
              - logs:DescribeLogStreams
            effect: Allow
            resource: arn:aws:logs:*:*:*
      secretRef:
        name: <your_role_name>
        namespace: openshift-logging
      serviceAccountNames:
        - logcollector

  2. 使用 ccoctl 命令,使用 CredentialsRequest CR 为 AWS 创建角色。使用 CredentialsRequest 对象时,这个 ccoctl 命令会创建一个带有信任策略的 IAM 角色,该角色与指定的 OIDC 身份提供程序相关联,以及一个授予对 CloudWatch 资源执行操作的权限策略。此命令在 /<path_to_ccoctl_output_dir>/manifests/openshift-logging-<your_role_name>-credentials.yaml 中创建了一个 YAML 配置文件。此 secret 文件包含与 AWS IAM 身份提供程序进行身份验证时使用的 role_arn 键/值。

    $ ccoctl aws create-iam-roles \
    --name=<name> \
    --region=<aws_region> \
    --credentials-requests-dir=<path_to_directory_with_list_of_credentials_requests>/credrequests \
    --identity-provider-arn=arn:aws:iam::<aws_account_id>:oidc-provider/<name>-oidc.s3.<aws_region>.amazonaws.com 1
    1
    <name> 是用于标记云资源的名称,应该与 STS 集群安装过程中使用的名称匹配
  3. 应用创建的 secret:

    $ oc apply -f output/manifests/openshift-logging-<your_role_name>-credentials.yaml
  4. 创建或编辑 ClusterLogForwarder 自定义资源:

    apiVersion: "logging.openshift.io/v1"
    kind: ClusterLogForwarder
    metadata:
      name: instance 1
      namespace: openshift-logging 2
    spec:
      outputs:
       - name: cw 3
         type: cloudwatch 4
         cloudwatch:
           groupBy: logType 5
           groupPrefix: <group prefix> 6
           region: us-east-2 7
         secret:
            name: <your_role_name> 8
      pipelines:
        - name: to-cloudwatch 9
          inputRefs: 10
            - infrastructure
            - audit
            - application
          outputRefs:
            - cw 11
    1
    ClusterLogForwarder CR 的名称必须是 instance
    2
    ClusterLogForwarder CR 的命名空间必须是 openshift-logging
    3
    指定输出的名称。
    4
    指定 cloudwatch 类型。
    5
    可选:指定如何对日志进行分组:
    • logType 为每个日志类型创建日志组
    • namespaceName 为每个应用程序命名空间创建一个日志组。基础架构和审计日志不受影响,剩余的日志按照 logType 分组。
    • namespaceUUID 为每个应用命名空间 UUID 创建一个新的日志组。它还会为基础架构和审计日志创建单独的日志组。
    6
    可选:指定一个字符串来替换日志组名称中的默认 infrastructureName 前缀。
    7
    指定 AWS 区域。
    8
    指定包含 AWS 凭证的 secret 名称。
    9
    可选:指定管道的名称。
    10
    使用管道指定要转发的日志类型:applicationinfrastructureaudit
    11
    指定使用此管道转发日志时使用的输出名称。

其他资源

11.12.1.1. 使用现有 AWS 角色为 AWS CloudWatch 创建 secret

如果您有一个 AWS 的现有角色,您可以使用 oc create secret --from-literal 命令为 AWS 使用 STS 创建 secret。

流程

  • 在 CLI 中,输入以下内容来为 AWS 生成 secret:

    $ oc create secret generic cw-sts-secret -n openshift-logging --from-literal=role_arn=arn:aws:iam::123456789012:role/my-role_with-permissions

    Secret 示例

    apiVersion: v1
    kind: Secret
    metadata:
      namespace: openshift-logging
      name: my-secret-name
    stringData:
      role_arn: arn:aws:iam::123456789012:role/my-role_with-permissions