附註:

在 OCI 中啟用 Amazon S3 相容後端的 Terraform 狀態檔鎖定

簡介

在雲端運算的動態世界中,基礎架構即程式碼 (IaC) 已成為尋求有效管理基礎架構組織的重要方法。IaC 的主要優勢在於它能夠促進一致性、自動化、版本控制和協作,使其成為雲端原生 IT 策略不可或缺的元素。

Terraform 作為著名的 IaC 工具,它會將基礎架構物件及其相依性的描述儲存在名為 terraform.tfstate 的組態檔中。在多個團隊成員管理雲端基礎架構的協作環境中,將 terraform.tfstate 儲存在本機會變得充滿挑戰。為解決此問題,Terraform 提供一個稱為「遠端後端」的功能,可在共用位置啟用狀態檔的儲存。部分後端在執行 planapply 作業時支援 tfstate 鎖定,以確保資料完整性並避免發生衝突。

本教學課程將著重於如何設定 S3 相容後端ScyllaDB 的 DynamoDB 相容 API 以啟用狀態檔鎖定。

目標

必要條件

方法 1:自動部署

按一下下方的部署至 Oracle Cloud ,輸入必要的詳細資訊,然後按一下套用

部署至 OCI

方法 2:手動部署

工作 1:設定 ScyllaDB 並啟用 DynamoDB 相容的 API

我們將建立以 ARM 為基礎的執行處理、安裝 Docker,以及設定和執行 ScyllaDB。

作業 1.1:佈建新的執行處理

  1. 瀏覽至 OCI 主控台中的執行處理頁面,然後按一下建立執行處理

  2. 請考慮下列建議,輸入必要的組態參數。

    • 影像Oracle Linux 8

    • 資源配置VM.Standard.A1.Flex (1 OCPU, 6 GB RAM)

    • 主要 VNICPublic Subnet & Assign Public IPv4 Address (將用於 SSH 連線)

    記下執行處理的公用和專用 IP 位址。

Task 1.2:安裝 Docker

  1. 透過 SSH 連線至執行處理。

    $ ssh opc@<public-ip-address-of-the-instance>
    
  2. 安裝 Docker Engine、containerd 以及 Docker Compose。

    sudo yum install -y yum-utils
    sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
    sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
    sudo systemctl start docker.service
    sudo systemctl enable docker.service
    sudo usermod -aG docker opc
    
  3. 重新連線 SSH 階段作業並驗證 Docker 的成功安裝。

    docker run hello-world
    
    # Unable to find image 'hello-world:latest' locally
    # latest: Pulling from library/hello-world
    # 70f5ac315c5a: Pull complete
    # Digest: sha256:3155e04f30ad5e4629fac67d6789f8809d74fea22d4e9a82f757d28cee79e0c5
    # Status: Downloaded newer image for hello-world:latest
    
    # Hello from Docker!
    # This message shows that your installation appears to be working correctly.
    

作業 1.3:產生客戶秘密金鑰

必須提供客戶秘密金鑰,才能使用 S3 相容 API 存取 OCI 物件儲存。

  1. 瀏覽至 OCI 主控台中的使用者設定檔頁面,然後選取客戶秘密金鑰

  2. 產生新金鑰、複製秘密金鑰值,然後按一下關閉

  3. 複製存取金鑰值 (此清單中的第二欄與客戶秘密金鑰)。

工作 1.4:設定並啟動 ScyllaDB

  1. 建立部署目錄 s3-lock

    mkdir s3-lock
    cd s3-lock
    
  2. 使用下列指令建立 .env

    AWS_ACCESS_KEY_ID='<ACCESS_KEY>'
    AWS_SECRET_ACCESS_KEY='<SECRET_KEY>'
    TF_STATE_TABLE='s3-locking-demo'
    

    注意:Docker 將使用 .env 檔案來設定 ScyllaDB。

  3. 使用下列指令在 scylladb 目錄中建立 scylladb.Dockerfile 檔案。

    FROM scylladb/scylla:latest
    RUN echo "alternator_enforce_authorization: true" >> /etc/scylla/scylla.yaml
    ENTRYPOINT ["/docker-entrypoint.py"]
    
  4. 使用下列指令在 s3-lock 目錄中建立 docker-compose.yaml 檔案。

    version: "3.3"
    
    services:
      scylladb:
        build:
          dockerfile: scylladb.Dockerfile
          context: ./scylladb
        image: "local-scylla:latest"
        container_name: "scylladb"
        restart: always
        command: ["--alternator-port=8000", "--alternator-write-isolation=always"]
        ports:
          - "8000:8000"
          - "9042:9042"
    
      scylladb-load-user:
        image: "scylladb/scylla:latest"
        container_name: "scylladb-load-user"
        depends_on:
          - scylladb
        entrypoint: /bin/bash -c "sleep 60 && echo loading cassandra keyspace && cqlsh scylladb -u cassandra -p cassandra \
                                  -e \"INSERT INTO system_auth.roles (role,can_login,is_superuser,member_of,salted_hash) \
                                  VALUES ('${AWS_ACCESS_KEY_ID}',True,False,null,'${AWS_SECRET_ACCESS_KEY}');\""
    
      scylladb-create-table:
        image: "amazon/aws-cli"
        container_name: "create_table"
        depends_on:
          - scylladb
        env_file: .env
        entrypoint: /bin/sh -c "sleep 70 && aws dynamodb create-table --table-name ${TF_STATE_TABLE} \
                                --attribute-definitions AttributeName=LockID,AttributeType=S \
                                --key-schema AttributeName=LockID,KeyType=HASH --billing-mode=PAY_PER_REQUEST \
                                --region 'None' --endpoint-url=http://scylladb:8000"
    
  5. 複查目錄結構。

    $ tree -a .
    .
    ├── docker-compose.yaml
    ├── .env
    └── scylladb
        └── scylladb.Dockerfile
    
    1 directory, 3 files
    
  6. 啟動 ScyllaDB 服務。

    docker compose up -d
    
  7. 允許連接埠 8000 的內送連線。

    sudo firewall-cmd --add-port 8000/tcp --permanent
    
  8. 驗證 ScyllaDB 的連線。

    • 安裝 python3-pipboto3 套裝軟體。

      sudo yum install -y python3-pip
      python3 -m pip install --user boto3
      
    • 使用下列指令建立 script.py 檔案。

      import boto3
      
      endpoint_url = 'http://localhost:8000'
      aws_access_key_id = '<ACCESS_KEY>'
      aws_secret_access_key = '<SECRET_KEY>'
      table_name = "s3-locking-demo"
      
      client = boto3.client('dynamodb', endpoint_url=endpoint_url, region_name="None",
                      aws_access_key_id=aws_access_key_id, aws_secret_access_key=aws_secret_access_key)
      
      response = client.describe_table(TableName=table_name)
      
      print(response["Table"]["TableName"], response["Table"]["TableStatus"])
      
    • 使用下列命令來執行命令檔。

      python3 script.py
      

    如果命令檔執行傳回 s3-locking-demo ACTIVE,則會如預期般運作。

作業 2:設定 OCI API 閘道以保護與 ScyllaDB DynamoDB 相容 API 的連線

在這項任務中,我們將設定 OCI API 閘道利用使用者與 ScyllaDB 之間的 TLS 加密。

作業 2.1:建立新的 API 閘道

  1. 瀏覽至 OCI 主控台中的 API 閘道頁面,然後按一下建立閘道

    • 名稱s3-locking

    • 類型public

    • 網路:與 ScyllaDB 執行處理相同的 VCN 和子網路

    • 憑證Default (*.oci.oci-customer.com)

  2. 寫下與新建 API 閘道關聯的主機名稱。當您按一下新建立的 API 閘道資源時,主機名稱會顯示在閘道資訊頁籤中。

    例如fj4etyuvz3s57jdsadsadsadsa.apigateway.eu-frankfurt-1.oci.customer-oci.com

作業 2.2:建立新的 API 閘道部署

  1. 建立新部署。

    1. 按一下新建立的 API 閘道,然後在左側功能表中,按一下資源下的部署

    2. 按一下建立建置,然後使用下列資訊建立新的建置。

      • 基本資訊

        • 名稱default

        • 路徑前置碼/

      • 認證:沒有認證

      • 路由

        • 路徑/{requested_path*}

        • 方法ANY

        • 後端類型HTTP

        • URL :http://<private_ip_address_of_the_instance>:8000/${request.path[requested_path]}

    3. 前往路由要求原則標頭轉換,然後按一下新增

      • 動作Set

      • 行為Overwrite

      • 標頭名稱Host

      • <API Gateway hostname> (例如:fj4etyuvz3s57jdsadsadsadsa.apigateway.eu-frankfurt-1.oci.customer-oci.com)

    4. 複查新部署的詳細資訊,然後按一下建立

  2. 設定子網路安全清單,以允許對連接埠 8000 進行傳入和傳出連線。

    1. 使用下列步驟取得配置給使用中子網路的 CIDR 區塊。

    2. 使用下列步驟識別與執行處理所使用子網路關聯的安全清單。

    3. 按一下已經與子網路關聯的預設安全清單,然後新增下列規則。

      • 傳入

        • 來源 CIDR0.0.0.0/0

        • 協定TCP

        • 目標連接埠範圍443

        • 說明Ingress Access to the API Gateway

      • 傳入

        • 來源 CIDR<subnet CIDR>

        • 協定TCP

        • 目標連接埠範圍8000

        • 說明Ingress connection to the ScyllaDB

      • 傳出

        • 目的地 CIDR<subnet CIDR>

        • 協定TCP

        • 目標連接埠範圍8000

        • 說明Egress connection from the API Gateway backend to ScyllaDB

工作 2.3:透過 API 閘道驗證 ScyllaDB 的連線

  1. 更新 script.py 檔案中的 endpoint_url 以使用 API 閘道主機名稱。例如:endpoint_url = "https://fj4etyuvz3s57jdsadsadsadsa.apigateway.eu-frankfurt-1.oci.customer-oci.com"

  2. 執行命令檔以測試公用端點的連線。

    python3 script.py
    s3-locking-demo ACTIVE
    

工作 3:使用 S3 相容 API 時測試 terraform.tfstate 檔案鎖定

我們會在想要執行 terraform 程式碼的執行處理上執行下列步驟。

  1. 複製以下各行並建立 main.tf 檔案。

    resource "null_resource" "hello_world" {
      provisioner "local-exec" {
        command = "echo Hello World"
      }
    
      provisioner "local-exec" {
        command = "echo 'sleeping for 30 seconds';sleep 30;echo 'done';"
      }
    
      triggers = {
        run_always = "${timestamp()}"
      }
    }
    
  2. 設定 S3 後端。

    terraform {
      backend "s3" {
        bucket = "<bucket-name>" # e.g.: bucket = "sample-bucket"
        region = "<oci-region>"  # e.g.: region = "eu-frankfurt-1"
    
        skip_region_validation      = true
        skip_credentials_validation = true
        skip_metadata_api_check     = true
        # skip_requesting_account_id  = true
        # skip_s3_checksum            = true
    
        force_path_style = true
        # use_path_style = true
        # insecure       = true
    
        # For best practice on how to set credentials access: https://developer.hashicorp.com/terraform/language/settings/backends/s3#access_key
    
        access_key = "<ACCESS_KEY>"
        secret_key = "<SECRET_KEY>"
    
        # endpoints = {
        #   # To determine <objectostrage_namespace> access: https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/understandingnamespaces.htm
        #   s3       = "https://<objectstorage_namespace>.compat.objectstorage.<oci-region>.oraclecloud.com"
        #   # e.g.: s3 = https://axaxnpcrorw5.compat.objectstorage.eu-frankfurt-1.oraclecloud.com
    
        #   # ScyllaDB TLS endpoint, configured using the API Gateway:
        #   dynamodb = "https://<API_Gateway_hostname>"
        #   # e.g.: dynamodb = "https://fj4etyuvz3s57jdsadsadsadsa.apigateway.eu-frankfurt-1.oci.customer-oci.com"
        # }
    
        # ScyllaDB TLS endpoint, configured using the API Gateway:
        dynamodb_endpoint = "https://<API_Gateway_hostname>"
        # e.g.: dynamodb_endpoint = "https://fj4etyuvz3s57jdsadsadsadsa.apigateway.eu-frankfurt-1.oci.customer-oci.com"
        key            = "demo.tfstate" # the name of the tfstate file
        dynamodb_table = "s3-locking-demo" # the name of the table in the ScyllaDB
      }
    }
    
  3. 使用 terraform init 指令初始化工作目錄。

    $ terraform init
    
    Initializing the backend...
    
    Successfully configured the backend "s3"! Terraform will automatically
    use this backend unless the backend configuration changes.
    
    Initializing provider plugins...
    - Finding latest version of hashicorp/null...
    - Installing hashicorp/null v3.2.2...
    - Installed hashicorp/null v3.2.2 (signed by HashiCorp)
    
    Terraform has created a lock file .terraform.lock.hcl to record the provider
    selections it made above. Include this file in your version control repository
    so that Terraform can guarantee to make the same selections by default when
    you run "terraform init" in the future.
    
    Terraform has been successfully initialized!
    
  4. 執行 terraform apply

    $ terraform apply
    
    Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
      + create
    
    Terraform will perform the following actions:
    
      # null_resource.hello_world will be created
      + resource "null_resource" "hello_world" {
          + id       = (known after apply)
          + triggers = {
              + "run_always" = (known after apply)
            }
        }
    
    Plan: 1 to add, 0 to change, 0 to destroy.
    
    Do you want to perform these actions?
      Terraform will perform the actions described above.
      Only 'yes' will be accepted to approve.
    
      Enter a value: yes
    
    null_resource.hello_world: Creating...
    null_resource.hello_world: Provisioning with 'local-exec'...
    null_resource.hello_world (local-exec): Executing: ["/bin/sh" "-c" "echo Hello World"]
    null_resource.hello_world (local-exec): Hello World
    null_resource.hello_world: Provisioning with 'local-exec'...
    null_resource.hello_world (local-exec): Executing: ["/bin/sh" "-c" "echo 'sleeping for 30 seconds';sleep 30;echo 'done';"]
    null_resource.hello_world (local-exec): sleeping for 30 seconds
    null_resource.hello_world: Still creating... [10s elapsed]
    null_resource.hello_world: Still creating... [20s elapsed]
    null_resource.hello_world: Still creating... [30s elapsed]
    null_resource.hello_world (local-exec): done
    null_resource.hello_world: Creation complete after 30s [id=5722520729023050684]
    
    Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
    
  5. 測試 terraform.tfstate 檔案鎖定。如果您在執行工作 3.4 時嘗試執行 terraform planterraform apply,您的要求將會被拒絕。

    $ terraform apply
    ╷
    │ Error: Error acquiring the state lock
    │
    │ Error message: operation error DynamoDB: PutItem, https response error StatusCode: 400, RequestID: ,
    │ ConditionalCheckFailedException: Failed condition.
    │ Lock Info:
    │   ID:        69309f13-d9fc-8c6b-9fbe-73639b340539
    │   Path:      sample-bucket/demo.tfstate
    │   Operation: OperationTypeApply
    │   Who:       use
    │   Version:   1.6.4
    │   Created:   2023-12-14 11:31:30.291168816 +0000 UTC
    │   Info:
    │
    │
    │ Terraform acquires a state lock to protect the state from being written
    │ by multiple users at the same time. Please resolve the issue above and try
    │ again. For most commands, you can disable locking with the "-lock=false"
    │ flag, but this is not recommended.
    
  6. 使用 DynamoDB API 管理 ScyllaDB 表格中的項目。如果您需要列出 DynamoDB 表格中的項目或手動移除項目,您可以在 script.py 檔案的結尾新增下列行。

    scan_response = client.scan(
        TableName=table_name,
    )
    
    print(scan_response)
    
    entry_to_delete = input("what is the LockID value you would like to delete? ")
    
    delete_response = client.delete_item(
        Key={
            'LockID': {
                'S': f'{entry_to_delete}',
            },
        },
        TableName=table_name
        )
    
    print(delete_response)
    

    注意this 命令檔提供更多功能。

認可

其他學習資源

瀏覽 docs.oracle.com/learn 的其他實驗室,或前往 Oracle Learning YouTube 頻道存取更多免費學習內容。此外,請造訪 education.oracle.com/learning-explorer 以成為 Oracle Learning Explorer。

如需產品文件,請造訪 Oracle Help Center