GVKun编程网logo

如何使用 terraform 将静态内部 ip 附加到计算实例(添加静态ip)

12

如果您想了解如何使用terraform将静态内部ip附加到计算实例和添加静态ip的知识,那么本篇文章将是您的不二之选。我们将深入剖析如何使用terraform将静态内部ip附加到计算实例的各个方面,并

如果您想了解如何使用 terraform 将静态内部 ip 附加到计算实例添加静态ip的知识,那么本篇文章将是您的不二之选。我们将深入剖析如何使用 terraform 将静态内部 ip 附加到计算实例的各个方面,并为您解答添加静态ip的疑在这篇文章中,我们将为您介绍如何使用 terraform 将静态内部 ip 附加到计算实例的相关知识,同时也会详细的解释添加静态ip的运用方法,并给出实际的案例分析,希望能帮助到您!

本文目录一览:

如何使用 terraform 将静态内部 ip 附加到计算实例(添加静态ip)

如何使用 terraform 将静态内部 ip 附加到计算实例(添加静态ip)

如何解决如何使用 terraform 将静态内部 ip 附加到计算实例?

嘿伙计们, 我想创建一个具有静态内部 IP 的计算实例,因此为了做到这一点,我在资源下方创建了

provider "google" {
  project     = "fit-visitor-305606"
  credentials = "${file("C:/Users/Rohan/Desktop/gvpc/fit.json")}"
  region      = "asia-south1"
}
resource "google_compute_network" "default" {
  name = "my-network"
}
resource "google_compute_subnetwork" "default" {
  name          = "my-subnet"
  ip_cidr_range = "10.0.0.0/16"  # 10.0.1.0
  region        = "asia-south1"
  network       = google_compute_network.default.id
}

resource "google_compute_address" "internal_with_subnet_and_address" {
  name         = "my-internal-address"
  subnetwork   = google_compute_subnetwork.default.id
  address_type = "INTERNAL"
  address      = "10.0.42.42"
  region       = "asia-south1"
}

resource "google_compute_instance" "default" {
  name         = "test"
  machine_type = "e2-medium"
  zone         = "asia-south1-a"
  tags = ["foo","bar"]

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-9"
    }
  }

  // Local SSD disk
  scratch_disk {
    interface = "SCSI"
  }

  network_interface {
    network = google_compute_network.default.id


    access_config {
      nat_ip = google_compute_address.internal_with_subnet_and_address.address
    }
  }

  Metadata = {
    foo = "bar"
  }

  Metadata_startup_script = "echo hi > /test.txt"
}

但是一旦我运行这个文件,它就会说

error

但VPC创建成功但无法附加到计算引擎

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

docker – 如何使用nginx和terraform配置两个实例?

docker – 如何使用nginx和terraform配置两个实例?

我有这个代码:

resource "docker_image" "Nginx" {                        
  name = "Nginx:1.11-alpine"                             
}                                                        
resource "docker_container" "Nginx-server" {          
  name = "Nginx-server"                               
  image = "${docker_image.Nginx.latest}"              
  ports {                                             
    internal = 80                                     
    external = 80                                     
  }                                                   
  volumes {                                           
    container_path  = "/usr/share/Nginx/html"         
    host_path = "/home/scrapbook/tutorial/www"        
    read_only = true                                  
  }                                                   
} 

在一个terraform文件(.tf)中…我想配置在同一台服务器上的两个不同端口中提供的两个Web程序实例.

resource "docker_container" "odoo-iku_1" {                 
  name  = "odoo-iku 1"                                     
  image = "ikusolutions/odoo-iku:latest"                 
  links = ["db"]                                         
  ports {                                                
    external = 8070                                      
    internal = 8069                                   
  }    
}

resource "docker_container" "odoo-iku_2" {                 
  name  = "odoo-iku 2"                                     
  image = "ikusolutions/odoo-iku:latest"                 
  links = ["db"]                                         
  ports {                                                
    external = 8071                                      
    internal = 8069                                   
  }    
}

如何让Nginx将外部端口8070和8071用于域名?例如:端口8070指向https://iku.solutions,端口8071指向https://demo.iku.solutions

解决方法:

Nginx根据您配置的方式路由到达服务器的流量.
在您的情况下,您希望将Nginx配置为反向代理,根据他们尝试访问的服务器名称来路由请求.假设odoo-iku 1 odoo-iku 2的请求分别来自odoo-iku1.example.com和odoo-iku2.example.com,此配置应该适合您.

server {
  listen      8001 default_server;
  server_name odoo-iku1.example.com;
  location / {
    proxy_pass       http://127.0.0.1:8071;
  }
}

server {
  listen      8002 default_server;
  server_name odoo-iku2.example.com;
  location / {
    proxy_pass       http://127.0.0.1:8070;
  }
}

upstream main {
  server 127.0.0.1:8001;
  server 127.0.0.1:8002;
}

server {
  listen      80;
  server_name example.com;
  location / {
    proxy_pass http://main;
  }
}

py-libterraform 的使用和实现:一个 Terraform 的 Python 绑定

py-libterraform 的使用和实现:一个 Terraform 的 Python 绑定

本文同步发表于字节话云公众号。

初衷

在某个使用 Python 开发的业务中,涉及到 Terraform 的交互,具体有两个需求:

  • 需要调用 Terraform 的各种命令,以完成对资源的部署、销毁等操作
  • 需要解析 Terraform 配置文件(HCL 语法)的内容,分析里面的组成

对于前者,有一个名为 python-terraform 的开源库,它封装了 Terraform 的命令,当我们在代码中调用时,背后会新启一个进程执行 Terraform 的对应命令,并能返回命令退出码和捕获的 stdoutstderrpython-terraform 用起来虽然方便,但最大的缺点在于要求执行环境事先安装了 Terraform,而且新启进程也带来了额外的开销。

对于后者,尚未找到 Python 开源库能满足要求。

我希望能有一个库无需用户事先安装 Terraform,能在当前进程执行 Terraform 命令,而且还能解析 Terraform 配置文件,py-libterraform 就这样诞生了。

使用

在说明 py-libterraform 的实现原理之前,不妨先看看是如何安装和使用的。

它的安装十分简单,执行 pip 命令即可,支持 MacLinuxWindows,并支持 Python3.6 及以上版本:

$ pip install libterraform

py-libterraform 目前提供两个功能:TerraformCommand 用于执行 Terraform CLI,TerraformConfig 用于解析 Terraform 配置文件。后文将通过示例介绍这两个功能。假定当前有一个 sleep 文件夹,里面的 main.tf 文件内容如下:

variable "time1" {
  type = string
  default = "1s"
}

variable "time2" {
  type = string
  default = "1s"
}

resource "time_sleep" "wait1" {
  create_duration = var.time1
}

resource "time_sleep" "wait2" {
  create_duration = var.time2
}

output "wait1_id" {
  value = time_sleep.wait1.id
}

output "wait2_id" {
  value = time_sleep.wait2.id
}

Terraform CLI

现在进入 sleep 目录,需要对它执行 Terraform init, applyshow,以部署资源并查看资源属性,那么可以这么做:

>>> from libterraform import TerraformCommand
>>> cli = TerraformCommand()
>>> cli.init()
<CommandResult retcode=0 json=False>
>>> _.value
''\nInitializing the backend...\n\nInitializing provider plugins...\n- Reusing previous version of hashicorp/time from the dependency lock file\n- Using previously-installed hashicorp/time v0.7.2\n\nTerraform has been successfully initialized!\n\nYou may now begin working with Terraform. Try running "terraform plan" to see\nany changes that are required for your infrastructure. All Terraform commands\nshould now work.\n\nIf you ever set or change modules or backend configuration for Terraform,\nrerun this command to reinitialize your working directory. If you forget, other\ncommands will detect it and remind you to do so if necessary.\n''
>>> cli.apply()
<CommandResult retcode=0 json=True>
>>> _.value
[{''@level'': ''info'', ''@message'': ''Terraform 1.1.7'', ''@module'': ''terraform.ui'', ''@timestamp'': ''2022-04-08T19:16:59.984727+08:00'', ''terraform'': ''1.1.7'', ''type'': ''version'', ''ui'': ''1.0''}, ... ]
>>> cli.show()
<CommandResult retcode=0 json=True>
>>> _.value
{''format_version'': ''1.0'', ''terraform_version'': ''1.1.7'', ''values'': {''outputs'': {''wait1_id'': {''sensitive'': False, ''value'': ''2022-04-08T11:17:01Z''}, ''wait2_id'': {''sensitive'': False, ''value'': ''2022-04-08T11:17:01Z''}}, ''root_module'': {''resources'': [{''address'': ''time_sleep.wait1'', ''mode'': ''managed'', ''type'': ''time_sleep'', ''name'': ''wait1'', ''provider_name'': ''registry.terraform.io/hashicorp/time'', ''schema_version'': 0, ''values'': {''create_duration'': ''1s'', ''destroy_duration'': None, ''id'': ''2022-04-08T11:17:01Z'', ''triggers'': None}, ''sensitive_values'': {}}, {''address'': ''time_sleep.wait2'', ''mode'': ''managed'', ''type'': ''time_sleep'', ''name'': ''wait2'', ''provider_name'': ''registry.terraform.io/hashicorp/time'', ''schema_version'': 0, ''values'': {''create_duration'': ''1s'', ''destroy_duration'': None, ''id'': ''2022-04-08T11:17:01Z'', ''triggers'': None}, ''sensitive_values'': {}}]}}}

从上述执行过程可以看出,不论执行什么命令,都会返回一个 CommandResult 对象,用来表示命令执行结果(包含返回码、输出、错误输出、是否为 json 结构)。
其中:

  • init() 返回的 value 是 Terraform init 命令的标准输出,一个字符串
  • apply() 返回的 value 默认是 Terraform apply -json 命令的标准输出被视作 json 加载后的数据,一个展示日志记录的列表。如果不希望解析标准输出,则可以使用 apply(json=False)
  • show() 返回的 value 默认是 Terraform show -jon 命令的标准输出被视作 json 加载后的数据,一个展示 Terraform state 文件数据结构的字典

所有命令的封装函数的思路是尽可能让结果方便给程序处理,因此对于支持 -json 的 Terraform 命令都会默认使用此选项并对结果进行解析。

以上是一个简单的示例,实际上 TerraformCommand 封装了所有的 Terraform 命令,具体可以调用 help(TerraformCommand) 进行查看。

Terraform 配置文件解析

如果希望拿到 Terraform 对配置文件的解析结果做进一步处理,那么 TerraformConfig 就可以满足需求,通过它可以解析指定的 Terraform 配置目录,获取其中的变量、资源、输出、行号等信息,这对分析配置组成很有帮助。可以这么做(部分输出较多使用...做了省略):

>>> from libterraform import TerraformConfig
>>> mod, _ = TerraformConfig.load_config_dir(''.'')
>>> mod
{''SourceDir'': ''.'', ''CoreVersionConstraints'': None, ''ActiveExperiments'': {}, ''Backend'': None, ''CloudConfig'': None, ''ProviderConfigs'': None, ''ProviderRequirements'': {''RequiredProviders'': {}, ''DeclRange'': ...}, ''Variables'': {''time1'': ..., ''time2'': ...}, ''Locals'': {}, ''Outputs'': {''wait1_id'': ..., ''wait2_id'': ...}, ''ModuleCalls'': {}, ''ManagedResources'': {''time_sleep.wait1'': ..., ''time_sleep.wait2'': ...}, ''DataResources'': {}, ''Moved'': None}

TerraformConfig.load_config_dir 背后会调用 Terraform 源码中 internal/configs/parser_config_dir.go 中的 LoadConfigDir 方法,以加载 Terraform 配置文件目录,返回内容是原生返回结果 *Module, hcl.Diagnostics 的经序列化后分别加载为 Python 中的字典。

实现原理

由于 Terraform 是用 GoLang 编写的,Python 无法直接调用,但好在它可以编译为动态链接库,然后再被 Python 加载调用。因此,总体思路上可以这么做:

  • 使用 cgo 编写 Terraform 的 C 接口文件
  • 将它编译为动态链接库,Linux/Unix 上以 .so 结尾,在 Windows 上以 .dll 结尾
  • 在 Python 中通过 ctypes 加载此动态链接库,在此之上实现命令封装

本质上,GoLang 和 Python 之间以 C 作为媒介,完成交互。关于如何使用 cgoctypes 网上有很多文章,本文着重介绍实现过程中遇到的各种“坑”以及如何解决的。

坑 1:GoLang 的 internal packages 机制阻隔了外部调用

GoLang 从 1.4 版本开始,增加了 Internal packages 机制,只允许 internal 的父级目录及父级目录的子包导入,其它包无法导入。而 Terraform 最新版本中,几乎所有的代码都放在了 internal 中,这意味着使用 cgo 写的接口文件(本项目中叫 libterraform.go)如果作为外部包(比如包名叫 libterraform)是无法调用 Terraform 代码的,也就无法实现 Terraform 命令的封装。

一个解决方法是把 Terraform 中的 internal 改为 public,但这意味着需要修改大量的 Terraform 源码,这可不是个好主意。

那么另一个思路就是让 libterraform.go 作为整个 Terraform 项目的“一份子”,来“欺骗” Go 编译器。具体过程如下:

  • libterraform.go 的包名和 Terraform 主包保持一致,即 main
  • 构建前把 libterraform.go 移动到 Terraform 源码根目录下,作为 Terraform 项目的成员
  • 构建时,使用 go build -buildmode=c-shared -o=libterraform.so github.com/hashicorp/terraform 命令进行编译,这样编译出的动态链接库就能包含 libterraform.go 的逻辑

坑 2:注意管理 C 运行时申请的内存空间

不论是 GoLang 还是 Python,我们都不需要担心内存管理的问题,因为它们自会被语言的垃圾回收机制在合适的时机去回收。但是涉及到 C 的逻辑就需要各位注意内存管理了。
使用 cgo 中定义的接口中可能会返回 *C.char,它实际是 C 层面上开辟的一段内存空间,需要被显式释放。例如,libterraform.go 中定义了加载 Terraform 配置目录的方法 ConfigLoadConfigDir,其实现如下:

//export ConfigLoadConfigDir
func ConfigLoadConfigDir(cPath *C.char) (cMod *C.char, cDiags *C.char, cError *C.char) {
    defer func() {
        recover()
    }()

    parser := configs.NewParser(nil)
    path := C.GoString(cPath)
    mod, diags := parser.LoadConfigDir(path)
    modBytes, err := json.Marshal(convertModule(mod))
    if err != nil {
        cMod = C.CString("")
        cDiags = C.CString("")
        cError = C.CString(err.Error())
        return cMod, cDiags, cError
    }
    diagsBytes, err := json.Marshal(diags)
    if err != nil {
        cMod = C.CString(string(modBytes))
        cDiags = C.CString("")
        cError = C.CString(err.Error())
        return cMod, cDiags, cError
    }
    cMod = C.CString(string(modBytes))
    cDiags = C.CString(string(diagsBytes))
    cError = C.CString("")
    return cMod, cDiags, cError
}

上述方法实现中,使用 C.CString 会在 C 层面上申请了一段内存空间,并返回结果返回给调用者,那么调用者(Python 进程)需要在使用完返回值之后显式释放内存。

在此之前,需要先通过 cgo 暴露释放内存的方法:

//export Free
func Free(cString *int) {
    C.free(unsafe.Pointer(cString))
}

然后,在 Python 中就可以实现如下封装:

import os
from ctypes import cdll, c_void_p
from libterraform.common import WINDOWS


class LoadConfigDirResult(Structure):
    _fields_ = [("r0", c_void_p),
                ("r1", c_void_p),
                ("r2", c_void_p)]


_load_config_dir = _lib_tf.ConfigLoadConfigDir
_load_config_dir.argtypes = [c_char_p]
_load_config_dir.restype = LoadConfigDirResult

root = os.path.dirname(os.path.abspath(__file__))
_lib_filename = ''libterraform.dll'' if WINDOWS else ''libterraform.so''
_lib_tf = cdll.LoadLibrary(os.path.join(root, _lib_filename))

_free = _lib_tf.Free
_free.argtypes = [c_void_p]

def load_config_dir(path: str) -> (dict, dict):
    ret = _load_config_dir(path.encode(''utf-8''))
    r_mod = cast(ret.r0, c_char_p).value
    _free(ret.r0)
    r_diags = cast(ret.r1, c_char_p).value
    _free(ret.r1)
    err = cast(ret.r2, c_char_p).value
    _free(ret.r2)
    ...

这里,在获取到返回结果后,调用 _free (也就是 libterraform.go 中的 Free)来显式释放内存,从而避免内存泄露。

坑 3:捕获输出

在 Terraform 的源码中,执行命令的输出会打印到标准输出 stdout 和标准错误输出 stderr 上,那么使用 cgo 封装出 RunCli 的接口,并被 Python 调用时,默认情况下就直接输出到 stdoutstderr 上了。

这会有什么问题呢?如果同时执行两个命令,输出结果会交错,没法区分这些结果是哪个命令的结果。

解决思路就是使用管道:

  • 在 Python 进程中使用 os.pipe 分别创建用于标准输出和标准错误输出的管道(会生成文件描述符)
  • 将两个文件描述符传入到 libterraform.goRunCli 方法中,在内部使用 os.NewFile 打开两个文件描述符,并分别替换 os.Stdoutos.Stderr
  • RunCli 方法结束时关闭这两个文件,并恢复原始的 os.Stdoutos.Stderr

此外,使用 os.pipe 获取到的文件描述符给 libterraform.go 使用时要注意操作系统的不同:

  • 对于 Linux/Unix 来说,直接传进去使用即可
  • 对于 Windows 来说,需要额外将文件描述符转换成文件句柄,这是因为在 Windows 上 GoLang 的 os.NewFile 接收的是文件句柄

Python 中相关代码如下:

if WINDOWS:
    import msvcrt
    w_stdout_handle = msvcrt.get_osfhandle(w_stdout_fd)
    w_stderr_handle = msvcrt.get_osfhandle(w_stderr_fd)
    retcode = _run_cli(argc, c_argv, w_stdout_handle, w_stderr_handle)
else:
    retcode = _run_cli(argc, c_argv, w_stdout_fd, w_stderr_fd)

坑 4:管道 Hang

由于管道的大小有限制,如果写入超过了限制就会导致写 Hang。因此不能在调用 RunCli (即会把命令输出写入管道)之后去管道中读取输出,否则会发现在执行简单命令(如version)时正常,在执行复杂命令(如apply,因为有大量输出)时会 Hang 住。

解决思路就是在调用 RunCli 前就启动两个线程分别读取标准输出和标准错误输出的文件描述符内容,在调用 RunCli 命令之后去 join 这两个线程。Python 中相关代码如下:

r_stdout_fd, w_stdout_fd = os.pipe()
r_stderr_fd, w_stderr_fd = os.pipe()

stdout_buffer = []
stderr_buffer = []
stdout_thread = Thread(target=cls._fdread, args=(r_stdout_fd, stdout_buffer))
stdout_thread.daemon = True
stdout_thread.start()
stderr_thread = Thread(target=cls._fdread, args=(r_stderr_fd, stderr_buffer))
stderr_thread.daemon = True
stderr_thread.start()

if WINDOWS:
    import msvcrt
    w_stdout_handle = msvcrt.get_osfhandle(w_stdout_fd)
    w_stderr_handle = msvcrt.get_osfhandle(w_stderr_fd)
    retcode = _run_cli(argc, c_argv, w_stdout_handle, w_stderr_handle)
else:
    retcode = _run_cli(argc, c_argv, w_stdout_fd, w_stderr_fd)

stdout_thread.join()
stderr_thread.join()
if not stdout_buffer:
    raise TerraformFdReadError(fd=r_stdout_fd)
if not stderr_buffer:
    raise TerraformFdReadError(fd=r_stderr_fd)
stdout = stdout_buffer[0]
stderr = stderr_buffer[0]

最后

当发现现有的开源库满足不了需求时,手撸了 py-libterraform,基本实现了在单进程中调用 Terraform 命令的要求。尽管在开发过程中遇到了各种问题,并需要不断在 Python、GoLang、C 之间跳转,但好在一个个解决了,记录此过程若能让大家少“踩坑”也算值啦!

最后,https://github.com/Prodesire/... 求赞~

Terraform Azure提供程序-如何通过terraform为我的密钥库添加多个密钥和/或秘密?

Terraform Azure提供程序-如何通过terraform为我的密钥库添加多个密钥和/或秘密?

要为密钥库添加多个密钥或机密,您只需多次添加资源azurerm_key_vault_keyazurerm_key_vault_secret

建议在循环中创建此类资源。 Terraform提供了几种不同的循环结构,每种结构都打算在稍微不同的情况下使用:

  • count参数:遍历资源。
  • for_each表达式:遍历资源和资源中的内联块。
  • for表达式:循环遍历列表和地图。

例如,使用count参数创建一个或多个密钥和机密。

variable "key_lists" {
    type = list(string)
    default = ["key1","key2","key3"]
    
}

variable "secret_maps" {
    type = map(string)
    default = {
        "name1"= "value1"
        "aaa" = "111"
        "bbb" = "222"
    }
}

resource "azurerm_key_vault_key" "generated" {
  count        = length(var.key_lists)
  name         = var.key_lists[count.index]
  key_vault_id = azurerm_key_vault.example.id
  key_type     = "RSA"
  key_size     = 2048

  key_opts = [
    "decrypt","encrypt","sign","unwrapKey","verify","wrapKey",]
}

resource "azurerm_key_vault_secret" "example" {
  count = length(var.secret_maps)
  name         = keys(var.secret_maps)[count.index]
  value        = values(var.secret_maps)[count.index]
  key_vault_id = azurerm_key_vault.example.id

}

您可以阅读this blog以获得更多Terraform循环提示。

Terraform 学习(一)安装 Terraform 并里用 Terraform 部署 nginx

Terraform 学习(一)安装 Terraform 并里用 Terraform 部署 nginx

安装 Terraform

以 centos 为例,执行以下命令安装 Terraform

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo yum -y install terraform

安装完成后执行

terraform version

正常显示 terraform 的版本,安装成功

Terraform v1.2.5
on linux_amd64

安装和启动 Docker

执行命令安装和启动 Docker

yum install docker
service docker start

启动完成后,查看 Docker 镜像,为空

docker ps -a

编写 tf 文件

# nginx.tf
terraform {
# 这里的感觉类似 java 的 import,引入了一个第三方的 provider
  required_providers {
    docker = {
      source  = "kreuzwerker/docker"
      version = "~> 2.13.0"
    }
  }
}

provider "docker" {}

resource "docker_image" "nginx" {
  name         = "nginx:latest"
  keep_locally = false
}

resource "docker_container" "nginx" {
  image = docker_image.nginx.latest
  name  = "tutorial"
  ports {
    internal = 80
    external = 8000
  }
}

在 tf 文件同一级目录下执行 init 和 apply 命令

terraform init
terraform apply

执行完成后查看 docker 镜像,可以看到 nginx 镜像

docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED         STATUS         PORTS                  NAMES
ef5a90e36dbc   41b0e86104ba   "/docker-entrypoint.…"   5 seconds ago   Up 4 seconds   0.0.0.0:8000->80/tcp   tutorial

通过 curl 查看 nginx 服务

$ curl http://localhost:8000
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

停止容器

执行

terraform destroy

然后查看 docker 容器,可以看到 nginx 容器已经不存在了

docker ps -a

今天关于如何使用 terraform 将静态内部 ip 附加到计算实例添加静态ip的介绍到此结束,谢谢您的阅读,有关docker – 如何使用nginx和terraform配置两个实例?、py-libterraform 的使用和实现:一个 Terraform 的 Python 绑定、Terraform Azure提供程序-如何通过terraform为我的密钥库添加多个密钥和/或秘密?、Terraform 学习(一)安装 Terraform 并里用 Terraform 部署 nginx等更多相关知识的信息可以在本站进行查询。

本文标签: