簡體   English   中英

如何在 azure devops CI/CD 管道中動態創建 s3 存儲桶

[英]How to create s3 buckets dynamically in azure devops CI/CD pipeline

我想根據 yaml 文件之一中提到的數據,通過 CI/CD 管道自動創建存儲桶的過程。 所以,我有 bucket.yaml 文件,其中包含所有存儲桶的名稱。 隨着將來添加更多存儲桶名稱,此文件會不斷更改。 目前,這就是 bucket.yaml 的樣子

BucketName:
    - test-bucket
    - test-bucket2
    - test-bucket3

我有一個 template.yaml 文件,它是用於創建 s3 存儲桶的 cloudformation 模板。 這是它的外觀:

Resources:
  S3Bucket:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Retain
    Properties:
      BucketName: This will come from bucket.yaml

現在,template.yaml 將從 bucket.yaml 文件中獲取存儲桶名稱,並應創建 3 個存儲桶,如 bucket.yaml 中所述。 如果有人在 bucket.yaml 中再添加 2 個存儲桶,則 template.yaml 也應該創建這 2 個新存儲桶。 此外,如果有人從 bucket.yaml 中刪除任何存儲桶名稱,那么這些存儲桶也應該被刪除。 我在研究中找不到過程,只是找到了零碎的信息。所以,在這里我有一些具體的問題,如果可以的話:

  1. 如何從 bucket.yaml 和 template.yaml 中獲取存儲桶名稱應該創建所有存儲桶。
  2. 如果有人在 bucket.yaml 中更新/添加/刪除存儲桶名稱,則 template.yaml 應相應地更新這些名稱。 另外,請解釋我將如何通過 Azure DevOps 中的 CI/CD 管道進行操作。
  1. 關於你的第一個問題:

如何從 bucket.yaml 和 template.yaml 中獲取存儲桶名稱應該創建所有存儲桶。

bucket.yaml ,您可以使用參數來設置BucketName

例如:

parameters:
- name: BucketName
  type: object
  default:
  - test-bucket
  - test-bucket2
  - test-bucket3

steps:
- ${{ each value in parameters.BucketName }}:
  - script: echo ${{ value }}

此處的步驟可以遍歷參數BucketName的值。

template.yaml中,您可以調用bucket.yaml ,如下所示。

trigger:
- main

extends:
  template: bucket.yaml
  1. 對於你的第二個問題:

如果有人在 bucket.yaml 中更新/添加/刪除存儲桶名稱,則 template.yaml 應相應地更新這些名稱。

沒有任何簡單的方法可以做到這一點。 您可以嘗試編寫一個腳本以在管道中運行以執行以下操作:

  • 列出所有已創建的存儲桶。 這是現有存儲桶的列表。
  • 將現有存儲桶列表與參數BucketName的值列表進行比較,檢查哪些存儲桶需要添加,哪些存儲桶需要刪除。
  • 如果參數中列出了存儲桶,但現有存儲桶中沒有,則應將此存儲桶創建為新存儲桶。
  • 如果某個存儲桶在現有存儲桶中但未在參數中列出,則應刪除該存儲桶。
BucketName:
                  - test-bucket
                  - test-bucket2
                  - test-bucket3

這些要求意味着所有 S3 存儲桶都將以相同的方式創建,並且不需要偏離給定的 Cloudformation 模板 ( AWS::S3::Bucket )。

這些要求要求我們跟蹤需要刪除哪些 S3 存儲桶。 Cloudformation 不會刪除 S3 存儲桶,因為 Cloudformation 模板片段包含保留的DeletionPolicy

解決方案:

可以以特定方式標記 S3 存儲桶,以將它們標識為當前 CI/CD 管道所擁有。 可以列出 S3 存儲桶,並以正確的方式標記所有 S3 存儲桶,但在存儲桶中不存在。然后可以刪除bucket.yaml


我個人會使用 AWS SDK 創建 CI/CD 管道所需的 S3 存儲桶並手動管理 S3 存儲桶刪除。 如果應用程序需要 S3 存儲桶,那么他們應該在其應用程序的 Cloudformation 堆棧中自己創建它,以便他們可以!引用它並按照他們想要的方式對其進行自定義(例如 rest 的加密、版本控制、生命周期規則等)。


技術說明:

要刪除 S3 存儲桶,還需要刪除其內容。 這將要求我們列出 S3 存儲桶中的所有對象,然后將其刪除。 Java SDK [這里]的一些文檔。 只有隨后調用 API 才能成功刪除 S3 存儲桶。

您可以讓 Cloudformation 使用自定義資源刪除您的 S3 對象。 也就是說,我沒有找到有趣的自定義資源 - 所以如果您可以在 CI/CD 管道中使用 AWS SDK,我可能會使用它。

用於刪除存儲桶內容的自定義資源在 Cloudformation 中可能如下所示:(它是一個自定義資源,類似於 Lambda。如果自定義資源被取消配置,Lambda 將刪除 S3 存儲桶內容)

 # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cfn-customresource.html
  # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/walkthrough-custom-resources-lambda-lookup-amiids.html
  ExampleBucketOperationCustomResource:
    Type: AWS::CloudFormation::CustomResource
    DependsOn: [Bucket, ExampleBucketOperationLambdaFunction]
    Properties:
      ServiceToken: !GetAtt ExampleBucketOperationLambdaFunction.Arn
      # Custom properties
      BucketToUse: !Ref S3BucketName
  ExampleBucketOperationLambdaFunctionExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: "ExampleBucketOperationLambda-ExecutionRole"
      Path: "/"
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Action:
              - sts:AssumeRole
            Principal:
              Service:
                - lambda.amazonaws.com
      Policies:
        - PolicyName: "ExampleBucketOperationLambda-CanAccessCloudwatchLogs"
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: arn:aws:logs:*:*:*
        - PolicyName: "ExampleBucketOperationLambda-S3BucketLevelPermissions"
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - s3:ListBucket
                Resource:
                  - !Sub "arn:aws:s3:::${S3BucketName}"
        - PolicyName: "ExampleBucketOperationLambda-S3ObjectLevelPermissions"
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - s3:DeleteObject
                  - s3:PutObject
                Resource:
                  - !Sub "arn:aws:s3:::${S3BucketName}/*"
  # Test payload:
  # {"RequestType":"Create","ResourceProperties":{"BucketToUse":"your-bucket-name"}}
  ExampleBucketOperationLambdaFunction:
    Type: AWS::Lambda::Function
    DependsOn: ExampleBucketOperationLambdaFunctionExecutionRole
    # DeletionPolicy: Retain
    Properties:
      FunctionName: "ExampleBucketOperationLambda"
      Role: !GetAtt ExampleBucketOperationLambdaFunctionExecutionRole.Arn
      Runtime: python3.8
      Handler: index.handler
      Timeout: 30
      Code:
        ZipFile: |
          import boto3
          import cfnresponse
          def handler(event, context):
              eventType = event["RequestType"]
              print("The event type is: " + str(eventType));
              bucketToUse = event["ResourceProperties"]["BucketToUse"]
              print("The bucket to use: " + str(bucketToUse));
              try:
                  # Requires s3:ListBucket permission
                  if (eventType in ["Delete"]):
                      print("Deleting everyting in bucket: " + str(bucketToUse));
                      s3Client = boto3.client("s3")
                      s3Bucket = boto3.resource("s3").Bucket(bucketToUse)
                      for currFile in s3Bucket.objects.all():
                          print("Deleting file: " + currFile.key);
                          s3Client.delete_object(Bucket=bucketToUse, Key=currFile.key)
                  
                  print("All done")
                  responseData = {}
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)
              except Exception as e:
                  responseData = {}
                  errorDetail = "Exception: " + str(e)
                  errorDetail = errorDetail + "\n\t More detail can be found in CloudWatch Log Stream: " + context.log_stream_name
                  print(errorDetail)
                  cfnresponse.send(event=event, context=context, responseStatus=cfnresponse.FAILED, responseData=responseData, reason=errorDetail)

感謝以上回答。 我采取了不同的方式來解決這個問題。 我使用AWS CDK來實現我真正想要的。 我個人將 AWS CDK 用於 Python 並使用它創建了基礎設施。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM