注意:
- 此教程需要访问 Oracle Cloud。要注册免费账户,请参阅开始使用 Oracle Cloud Infrastructure Free Tier 。
- 它使用 Oracle Cloud Infrastructure 身份证明、租户和区间示例值。完成实验室时,请将这些值替换为特定于云环境的值。
在 OCI 中使用 Amazon S3 兼容后端启用 Terraform 状态文件锁定
简介
在云计算的动态世界中,基础设施即代码 (IaC) 已成为寻求有效管理基础设施的组织的关键方法。IaC 的主要优势在于它能够促进一致性、自动化、版本控制和协作,使其成为云原生 IT 战略不可或缺的要素。
Terraform 作为一个突出的 IaC 工具脱颖而出,它将基础结构对象及其依赖项的描述存储在名为 terraform.tfstate 的配置文件中。在多个团队成员管理云基础设施的协作环境中,将 terraform.tfstate 存储在本地变得非常具有挑战性。为了解决此问题,Terraform 提供了一种名为“远程后端”的功能,可用于在共享位置存储状态文件。某些后端在运行 plan 或 apply 操作时支持 tfstate 锁定,以确保数据完整性并防止冲突。
本教程将重点介绍如何设置 S3 兼容后端和 ScyllaDB 的 DynamoDB 兼容 API 以启用状态文件锁定。
目标
-
使用 Docker Compose 将 ScyllaDB 部署到实例。
-
配置与 Terraform S3 兼容的后端以支持
tfstate文件锁定。
先决条件
方法 1:自动部署
单击下面的部署到 Oracle Cloud ,输入所需详细信息并单击应用。
方法 2:手动部署
任务 1:设置 ScyllaDB 并启用与 DynamoDB 兼容的 API
我们将创建一个基于 ARM 的实例,安装 Docker,并配置和运行 ScyllaDB。
任务 1.1:预配新实例
-
导航到 OCI 控制台中的实例页,然后单击创建实例。
-
根据以下建议输入所需的配置参数。
-
图像:
Oracle Linux 8 -
配置:
VM.Standard.A1.Flex (1 OCPU, 6 GB RAM) -
主要 VNIC :
Public Subnet & Assign Public IPv4 Address(将用于 SSH 连接)
记下实例的公共和专用 IP 地址。
-
任务 1.2:安装 Docker
-
通过 SSH 连接到实例。
$ ssh opc@<public-ip-address-of-the-instance> -
安装 Docker 引擎、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 -
重新连接 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 对象存储,需要提供客户密钥。
-
在 OCI 控制台中导航到您的用户概要信息页,然后选择客户密钥。
-
生成新密钥,复制密钥值,然后单击关闭。
-
复制访问键值(此列表中的第二列带有客户密钥)。
任务 1.4:配置并启动 ScyllaDB
-
创建部署目录
s3-lock。mkdir s3-lock cd s3-lock -
使用以下命令创建
.env。AWS_ACCESS_KEY_ID='<ACCESS_KEY>' AWS_SECRET_ACCESS_KEY='<SECRET_KEY>' TF_STATE_TABLE='s3-locking-demo'注:Docker 编写用来设置 ScyllaDB 的
.env文件。 -
使用以下命令在目录
scylladb中创建文件scylladb.Dockerfile。FROM scylladb/scylla:latest RUN echo "alternator_enforce_authorization: true" >> /etc/scylla/scylla.yaml ENTRYPOINT ["/docker-entrypoint.py"] -
使用以下命令在
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" -
查看目录结构。
$ tree -a . . ├── docker-compose.yaml ├── .env └── scylladb └── scylladb.Dockerfile 1 directory, 3 files -
启动 ScyllaDB 服务。
docker compose up -d -
允许与端口
8000建立入站连接。sudo firewall-cmd --add-port 8000/tcp --permanent -
验证与 ScyllaDB 的连接。
-
安装
python3-pip和boto3软件包。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 网关
-
导航到 OCI 控制台中的 API 网关页面,然后单击创建网关。
-
名称:
s3-locking -
类型:
public -
网络:与 ScyllaDB 实例相同的 VCN 和子网
-
证书:
Default (*.oci.oci-customer.com)
-
-
写下与新创建的 API 网关关联的主机名。单击新建的 API 网关资源时,主机名将显示在网关信息选项卡中。
例如:
fj4etyuvz3s57jdsadsadsadsa.apigateway.eu-frankfurt-1.oci.customer-oci.com
任务 2.2:创建新的 API 网关部署
-
创建新部署。
-
单击新建的 API 网关,然后在左侧菜单中,单击资源下的部署。
-
单击创建部署并使用以下信息创建新部署。
-
基本信息
-
名称:
default -
路径前缀:
/
-
-
验证:无验证
-
路由
-
路径:
/{requested_path*} -
方法:
ANY -
后端类型:
HTTP -
URL :
http://<private_ip_address_of_the_instance>:8000/${request.path[requested_path]}
-
-
-
转到路由请求策略、标头转换,然后单击添加。
-
操作:
Set -
行为:
Overwrite -
标题名称:
Host -
值:
<API Gateway hostname>(例如:fj4etyuvz3s57jdsadsadsadsa.apigateway.eu-frankfurt-1.oci.customer-oci.com)
-
-
查看新部署的详细信息,然后单击创建。
-
-
设置子网安全列表以允许与端口
8000建立入站和出站连接。-
使用以下步骤获取分配给正在使用的子网的 CIDR 块。
-
使用以下步骤标识与实例使用的子网关联的安全列表。
-
单击已与子网关联的默认安全列表并添加以下规则。
-
入站
-
源 CIDR :
0.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 的连接
-
更新文件
script.py中的endpoint_url以使用 API 网关主机名。例如:endpoint_url = "https://fj4etyuvz3s57jdsadsadsadsa.apigateway.eu-frankfurt-1.oci.customer-oci.com" -
运行脚本以测试与公共端点的连接。
python3 script.py s3-locking-demo ACTIVE
任务 3:使用 S3 兼容 API 时测试 terraform.tfstate 文件锁定
我们将对要运行 terraform 代码的实例执行以下步骤。
-
复制以下行并创建文件
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()}" } } -
配置 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 } } -
使用
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! -
执行
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. -
测试
terraform.tfstate文件锁定。如果在执行任务 3.4 期间尝试执行terraform plan或terraform 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. -
使用 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)注意:此脚本中提供了更多功能。
相关链接
确认
- 作者 - Andrei Ilas(首席云架构师)
更多学习资源
浏览 docs.oracle.com/learn 上的其他实验室,或者通过 Oracle Learning YouTube 频道访问更多免费学习内容。此外,请访问 education.oracle.com/learning-explorer 以成为 Oracle Learning Explorer。
有关产品文档,请访问 Oracle 帮助中心。
Enable Terraform State File Locking with Amazon S3 Compatible Backend in OCI
F90992-01
January 2024
Copyright © 2024, Oracle and/or its affiliates.