Managing Applications and Infrastructure with Terraform-Deploying Infrastructure with Terraform-(1)Terraform Basics and a Docker Deployment-(13)Terraform Workspaces

2018年10月04日

*
Managing Applications and Infrastructure with Terraform-Deploying Infrastructure with Terraform
1. Terraform Basics and a Docker Deployment
13. Terraform Workspaces

~/docker# terraform apply

var.env
  env: dev or prod

  Enter a value: dev


An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # module.container.docker_container.container_id will be created
  + resource "docker_container" "container_id" {
      + attach           = false
      + bridge           = (known after apply)
      + command          = (known after apply)
      + container_logs   = (known after apply)
      + dns              = (known after apply)
      + dns_opts         = (known after apply)
      + entrypoint       = (known after apply)
      + exit_code        = (known after apply)
      + gateway          = (known after apply)
      + hostname         = (known after apply)
      + id               = (known after apply)
      + image            = (known after apply)
      + ip_address       = (known after apply)
      + ip_prefix_length = (known after apply)
      + ipc_mode         = (known after apply)
      + log_driver       = (known after apply)
      + log_opts         = (known after apply)
      + logs             = false
      + must_run         = true
      + name             = "dev_blog"
      + network_data     = (known after apply)
      + read_only        = false
      + restart          = "no"
      + rm               = false
      + shm_size         = (known after apply)
      + start            = true
      + user             = (known after apply)
      + working_dir      = (known after apply)

      + ports {
          + external = 8080
          + internal = 2368
          + ip       = "0.0.0.0"
          + protocol = "tcp"
        }
    }

  # module.image.docker_image.image_id will be created
  + resource "docker_image" "image_id" {
      + id     = (known after apply)
      + latest = (known after apply)
      + name   = "ghost:latest"
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + IP_Address     = (known after apply)
  + container_name = "dev_blog"

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

module.image.docker_image.image_id: Creating...
module.image.docker_image.image_id: Still creating... [10s elapsed]
module.image.docker_image.image_id: Still creating... [20s elapsed]
module.image.docker_image.image_id: Creation complete after 29s [id=sha256:98c65d66926b2da9fbb696d43aadfaf3fee847b7185e132e199532bc549aeba5ghost:latest]
module.container.docker_container.container_id: Creating...
module.container.docker_container.container_id: Creation complete after 1s [id=b1fa2d496c2bfa811fa71640b067fcdb60ad8d04be2c4fe118941687b48911fd]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

IP_Address = 172.17.0.2
container_name = dev_blog

~/docker# terraform apply
var.env
  env: dev or prod

  Enter a value: prod

module.image.docker_image.image_id: Refreshing state... [id=sha256:98c65d66926b2da9fbb696d43aadfaf3fee847b7185e132e199532bc549aeba5ghost:latest]
module.container.docker_container.container_id: Refreshing state... [id=b1fa2d496c2bfa811fa71640b067fcdb60ad8d04be2c4fe118941687b48911fd]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # module.container.docker_container.container_id must be replaced
-/+ resource "docker_container" "container_id" {
        attach            = false
      + bridge            = (known after apply)
      ~ command           = [
          - "node",
          - "current/index.js",
        ] -> (known after apply)
      + container_logs    = (known after apply)
      - cpu_shares        = 0 -> null
      ~ dns               = [] -> (known after apply)
      ~ dns_opts          = [] -> (known after apply)
      - dns_search        = [] -> null
      ~ entrypoint        = [
          - "docker-entrypoint.sh",
        ] -> (known after apply)
      + exit_code         = (known after apply)
      ~ gateway           = "172.17.0.1" -> (known after apply)
      - group_add         = [] -> null
      ~ hostname          = "b1fa2d496c2b" -> (known after apply)
      ~ id                = "b1fa2d496c2bfa811fa71640b067fcdb60ad8d04be2c4fe118941687b48911fd" -> (known after apply)
        image             = "sha256:98c65d66926b2da9fbb696d43aadfaf3fee847b7185e132e199532bc549aeba5"
      ~ ip_address        = "172.17.0.2" -> (known after apply)
      ~ ip_prefix_length  = 16 -> (known after apply)
      ~ ipc_mode          = "private" -> (known after apply)
      - links             = [] -> null
      ~ log_driver        = "json-file" -> (known after apply)
      ~ log_opts          = {} -> (known after apply)
        logs              = false
      - max_retry_count   = 0 -> null
      - memory            = 0 -> null
      - memory_swap       = 0 -> null
        must_run          = true
      ~ name              = "dev_blog" -> "prod_blog" # forces replacement
      ~ network_data      = [
          - {
              - gateway          = "172.17.0.1"
              - ip_address       = "172.17.0.2"
              - ip_prefix_length = 16
              - network_name     = "bridge"
            },
        ] -> (known after apply)
      - network_mode      = "default" -> null
      - privileged        = false -> null
      - publish_all_ports = false -> null
        read_only         = false
        restart           = "no"
        rm                = false
      ~ shm_size          = 64 -> (known after apply)
        start             = true
      - sysctls           = {} -> null
      - tmpfs             = {} -> null
      + user              = (known after apply)
      ~ working_dir       = "/var/lib/ghost" -> (known after apply)

      ~ ports {
          ~ external = 8080 -> 80 # forces replacement
            internal = 2368
            ip       = "0.0.0.0"
            protocol = "tcp"
        }
    }

  # module.image.docker_image.image_id will be updated in-place
  ~ resource "docker_image" "image_id" {
        id     = "sha256:98c65d66926b2da9fbb696d43aadfaf3fee847b7185e132e199532bc549aeba5ghost:latest"
        latest = "sha256:98c65d66926b2da9fbb696d43aadfaf3fee847b7185e132e199532bc549aeba5"
      ~ name   = "ghost:latest" -> "ghost:alpine"
    }

Plan: 1 to add, 1 to change, 1 to destroy.

Changes to Outputs:
  ~ IP_Address     = "172.17.0.2" -> (known after apply)
  ~ container_name = "dev_blog" -> "prod_blog"

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: no

Apply cancelled.

~/docker# ls
container  image  main.tf  outputs.tf  terraform.tfstate  terraform.tfstate.backup  variables.tf

~/docker# cat terraform.tfstate
{
  "version": 4,
  "terraform_version": "0.13.4",
  "serial": 74,
  "lineage": "709353e2-1832-8aef-af95-42e941eeb58a",
  "outputs": {
    "IP_Address": {
      "value": "172.17.0.2",
      "type": "string"
    },
    "container_name": {
      "value": "dev_blog",
      "type": "string"
    }
  },
  "resources": [
    {
      "module": "module.container",
      "mode": "managed",
      "type": "docker_container",
      "name": "container_id",
      "provider": "provider[\"registry.terraform.io/terraform-providers/docker\"]",
      "instances": [
        {
          "schema_version": 2,
          "attributes": {
            "attach": false,
            "bridge": "",
            "capabilities": [],
            "command": [
              "node",
              "current/index.js"
            ],
            "container_logs": null,
            "cpu_set": "",
            "cpu_shares": 0,
            "destroy_grace_seconds": null,
            "devices": [],
            "dns": [],
            "dns_opts": [],
            "dns_search": null,
            "domainname": "",
            "entrypoint": [
              "docker-entrypoint.sh"
            ],
            "env": null,
            "exit_code": null,
            "gateway": "172.17.0.1",
            "group_add": null,
            "healthcheck": [],
            "host": [],
            "hostname": "b1fa2d496c2b",
            "id": "b1fa2d496c2bfa811fa71640b067fcdb60ad8d04be2c4fe118941687b48911fd",
            "image": "sha256:98c65d66926b2da9fbb696d43aadfaf3fee847b7185e132e199532bc549aeba5",
            "ip_address": "172.17.0.2",
            "ip_prefix_length": 16,
            "ipc_mode": "private",
            "labels": [],
            "links": null,
            "log_driver": "json-file",
            "log_opts": {},
            "logs": false,
            "max_retry_count": 0,
            "memory": 0,
            "memory_swap": 0,
            "mounts": [],
            "must_run": true,
            "name": "dev_blog",
            "network_alias": null,
            "network_data": [
              {
                "gateway": "172.17.0.1",
                "ip_address": "172.17.0.2",
                "ip_prefix_length": 16,
                "network_name": "bridge"
              }
            ],
            "network_mode": "default",
            "networks": null,
            "networks_advanced": [],
            "pid_mode": "",
            "ports": [
              {
                "external": 8080,
                "internal": 2368,
                "ip": "0.0.0.0",
                "protocol": "tcp"
              }
            ],
            "privileged": false,
            "publish_all_ports": false,
            "read_only": false,
            "restart": "no",
            "rm": false,
            "shm_size": 64,
            "start": true,
            "sysctls": null,
            "tmpfs": null,
            "ulimit": [],
            "upload": [],
            "user": "",
            "userns_mode": "",
            "volumes": [],
            "working_dir": "/var/lib/ghost"
          },
          "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjIifQ==",
          "dependencies": [
            "module.image.docker_image.image_id"
          ]
        }
      ]
    },
    {
      "module": "module.image",
      "mode": "managed",
      "type": "docker_image",
      "name": "image_id",
      "provider": "provider[\"registry.terraform.io/terraform-providers/docker\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "id": "sha256:98c65d66926b2da9fbb696d43aadfaf3fee847b7185e132e199532bc549aeba5ghost:latest",
            "keep_locally": null,
            "latest": "sha256:98c65d66926b2da9fbb696d43aadfaf3fee847b7185e132e199532bc549aeba5",
            "name": "ghost:latest",
            "pull_trigger": null,
            "pull_triggers": null
          },
          "private": "bnVsbA=="
        }
      ]
    }
  ]
}

~/docker# terraform destroy
var.env
  env: dev or prod

  Enter a value: dev

module.image.docker_image.image_id: Refreshing state... [id=sha256:98c65d66926b2da9fbb696d43aadfaf3fee847b7185e132e199532bc549aeba5ghost:latest]
module.container.docker_container.container_id: Refreshing state... [id=b1fa2d496c2bfa811fa71640b067fcdb60ad8d04be2c4fe118941687b48911fd]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # module.container.docker_container.container_id will be destroyed
  - resource "docker_container" "container_id" {
      - attach            = false -> null
      - command           = [
          - "node",
          - "current/index.js",
        ] -> null
      - cpu_shares        = 0 -> null
      - dns               = [] -> null
      - dns_opts          = [] -> null
      - dns_search        = [] -> null
      - entrypoint        = [
          - "docker-entrypoint.sh",
        ] -> null
      - gateway           = "172.17.0.1" -> null
      - group_add         = [] -> null
      - hostname          = "b1fa2d496c2b" -> null
      - id                = "b1fa2d496c2bfa811fa71640b067fcdb60ad8d04be2c4fe118941687b48911fd" -> null
      - image             = "sha256:98c65d66926b2da9fbb696d43aadfaf3fee847b7185e132e199532bc549aeba5" -> null
      - ip_address        = "172.17.0.2" -> null
      - ip_prefix_length  = 16 -> null
      - ipc_mode          = "private" -> null
      - links             = [] -> null
      - log_driver        = "json-file" -> null
      - log_opts          = {} -> null
      - logs              = false -> null
      - max_retry_count   = 0 -> null
      - memory            = 0 -> null
      - memory_swap       = 0 -> null
      - must_run          = true -> null
      - name              = "dev_blog" -> null
      - network_data      = [
          - {
              - gateway          = "172.17.0.1"
              - ip_address       = "172.17.0.2"
              - ip_prefix_length = 16
              - network_name     = "bridge"
            },
        ] -> null
      - network_mode      = "default" -> null
      - privileged        = false -> null
      - publish_all_ports = false -> null
      - read_only         = false -> null
      - restart           = "no" -> null
      - rm                = false -> null
      - shm_size          = 64 -> null
      - start             = true -> null
      - sysctls           = {} -> null
      - tmpfs             = {} -> null
      - working_dir       = "/var/lib/ghost" -> null

      - ports {
          - external = 8080 -> null
          - internal = 2368 -> null
          - ip       = "0.0.0.0" -> null
          - protocol = "tcp" -> null
        }
    }

  # module.image.docker_image.image_id will be destroyed
  - resource "docker_image" "image_id" {
      - id     = "sha256:98c65d66926b2da9fbb696d43aadfaf3fee847b7185e132e199532bc549aeba5ghost:latest" -> null
      - latest = "sha256:98c65d66926b2da9fbb696d43aadfaf3fee847b7185e132e199532bc549aeba5" -> null
      - name   = "ghost:latest" -> null
    }

Plan: 0 to add, 0 to change, 2 to destroy.

Changes to Outputs:
  - IP_Address     = "172.17.0.2" -> null
  - container_name = "dev_blog" -> null

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

module.container.docker_container.container_id: Destroying... [id=b1fa2d496c2bfa811fa71640b067fcdb60ad8d04be2c4fe118941687b48911fd]
module.container.docker_container.container_id: Destruction complete after 1s
module.image.docker_image.image_id: Destroying... [id=sha256:98c65d66926b2da9fbb696d43aadfaf3fee847b7185e132e199532bc549aeba5ghost:latest]
module.image.docker_image.image_id: Destruction complete after 10s

Destroy complete! Resources: 2 destroyed.

Manage workspaces.
Workspaces are managed with the terraform workspace set of commands. To create a new workspace and switch to it, you can use terraform workspace new; to switch workspaces you can use terraform workspace select; etc.
~/docker# terraform workspace new dev
Created and switched to workspace "dev"!

You're now on a new, empty workspace. Workspaces isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.

~/docker# terraform workspace new prod
Created and switched to workspace "prod"!

You're now on a new, empty workspace. Workspaces isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.

~/docker# terraform workspace select dev
Switched to workspace "dev".

The persistent data stored in the backend belongs to a workspace. Initially the backend has only one workspace, called "default", and thus there is only one Terraform state associated with that configuration.

Terraform starts with a single workspace named "default". This workspace is special both because it is the default and also because it cannot ever be deleted. If you've never explicitly used workspaces, then you've only ever worked on the "default" workspace.

~/docker# terraform workspace select default
Switched to workspace "default".

~/docker# terraform workspace select dev
Switched to workspace "dev".

~/docker# terraform apply
var.env
  env: dev or prod

  Enter a value: dev


An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # module.container.docker_container.container_id will be created
  + resource "docker_container" "container_id" {
      + attach           = false
      + bridge           = (known after apply)
      + command          = (known after apply)
      + container_logs   = (known after apply)
      + dns              = (known after apply)
      + dns_opts         = (known after apply)
      + entrypoint       = (known after apply)
      + exit_code        = (known after apply)
      + gateway          = (known after apply)
      + hostname         = (known after apply)
      + id               = (known after apply)
      + image            = (known after apply)
      + ip_address       = (known after apply)
      + ip_prefix_length = (known after apply)
      + ipc_mode         = (known after apply)
      + log_driver       = (known after apply)
      + log_opts         = (known after apply)
      + logs             = false
      + must_run         = true
      + name             = "dev_blog"
      + network_data     = (known after apply)
      + read_only        = false
      + restart          = "no"
      + rm               = false
      + shm_size         = (known after apply)
      + start            = true
      + user             = (known after apply)
      + working_dir      = (known after apply)

      + ports {
          + external = 8080
          + internal = 2368
          + ip       = "0.0.0.0"
          + protocol = "tcp"
        }
    }

  # module.image.docker_image.image_id will be created
  + resource "docker_image" "image_id" {
      + id     = (known after apply)
      + latest = (known after apply)
      + name   = "ghost:latest"
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Do you want to perform these actions in workspace "dev"?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

module.image.docker_image.image_id: Creating...
module.image.docker_image.image_id: Still creating... [10s elapsed]
module.image.docker_image.image_id: Still creating... [20s elapsed]
module.image.docker_image.image_id: Creation complete after 29s [id=sha256:98c65d66926b2da9fbb696d43aadfaf3fee847b7185e132e199532bc549aeba5ghost:latest]
module.container.docker_container.container_id: Creating...
module.container.docker_container.container_id: Creation complete after 2s [id=2c856cff5dc5316f16572c088d92bf38df8a0af7519d630cd6d12413ea33b34e]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

IP_Address = 172.17.0.2
container_name = dev_blog

~/docker# terraform workspace select prod
Switched to workspace "prod".

~/docker# terraform apply
var.env
  env: dev or prod

  Enter a value: prod


An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # module.container.docker_container.container_id will be created
  + resource "docker_container" "container_id" {
      + attach           = false
      + bridge           = (known after apply)
      + command          = (known after apply)
      + container_logs   = (known after apply)
      + dns              = (known after apply)
      + dns_opts         = (known after apply)
      + entrypoint       = (known after apply)
      + exit_code        = (known after apply)
      + gateway          = (known after apply)
      + hostname         = (known after apply)
      + id               = (known after apply)
      + image            = (known after apply)
      + ip_address       = (known after apply)
      + ip_prefix_length = (known after apply)
      + ipc_mode         = (known after apply)
      + log_driver       = (known after apply)
      + log_opts         = (known after apply)
      + logs             = false
      + must_run         = true
      + name             = "prod_blog"
      + network_data     = (known after apply)
      + read_only        = false
      + restart          = "no"
      + rm               = false
      + shm_size         = (known after apply)
      + start            = true
      + user             = (known after apply)
      + working_dir      = (known after apply)

      + ports {
          + external = 80
          + internal = 2368
          + ip       = "0.0.0.0"
          + protocol = "tcp"
        }
    }

  # module.image.docker_image.image_id will be created
  + resource "docker_image" "image_id" {
      + id     = (known after apply)
      + latest = (known after apply)
      + name   = "ghost:alpine"
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Do you want to perform these actions in workspace "prod"?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

module.image.docker_image.image_id: Creating...
module.image.docker_image.image_id: Still creating... [10s elapsed]
module.image.docker_image.image_id: Still creating... [20s elapsed]
module.image.docker_image.image_id: Creation complete after 26s [id=sha256:a7d409c8a8af50ce6df5cc5cb94600b657acc9cfd82216d89a83730467bdd439ghost:alpine]
module.container.docker_container.container_id: Creating...
module.container.docker_container.container_id: Creation complete after 2s [id=311610e3b765e81f3d2ad545198218f8768c2441eddcb62f82e7a1928eaf1621]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

IP_Address = 172.17.0.3
container_name = prod_blog

Access http://[PublicIP] and http://[PublicIP]:8080
Both URL could be successfully accessed.

~/docker# ls
container  image  main.tf  outputs.tf  terraform.tfstate  terraform.tfstate.backup  terraform.tfstate.d  variables.tf

~/docker# cd terraform.tfstate.d

Each Terraform configuration has an associated backend that defines how operations are executed and where persistent data such as the Terraform state are stored.
~/docker/terraform.tfstate.d# ls
dev  prod

~/docker/terraform.tfstate.d# cd ..


References

Command: workspace

Workspaces

Category: orchestration Tags: public

Upvote


Downvote