เอา Terraform state ไปเก็บไว้ใน postgres

Terrafrom State มีข้อมูลสำคัญ ต้องเอาไปเก็บไว้ในที่ที่ปลอดภัย

author image
drs

Technology evangelistic advocacy

Posted on 2023-12-02 00:51:47 +0700

โดยปกติ ผลของการทำงานของ terraform จะถูกจะถูกเขียนลงไฟล์ที่เรียกว่า terraform state จะถูกเก็บไว้ในไฟล์ที่ชื่อว่า terraform.tfstate ในไฟล์นั้นมีรายละเอียดต่าง ๆ อย่างครบถ้วนของ resource ที่ถูกระบุไว้ใน terraform configuration file ดังนั้นมีการสร้าง resource จำเป็นต้องใช้ข้อมูลที่เป็น sensitive information เช่นพวก password, private key ข้อมูลเหล่านี้ก็จะถูกเก็บไว้ใน tarraform state ไปด้วย ใครก็ตามที่เข้าถึงไฟล์นี้ได้ หรือจัดเก็บไว้แบบที่ไม่ระมัดระวัง ข้อมูลที่เป็น sensitive information อาจจะเกิดการรั่วไหลไปได้ ดังนั้น การบริหารจัดการ terraform state จึงมีการแนะนำให้ไปจัดกเก็บไว้ในส่วนที่เรียกว่า backend ซึ่งจะเป็นที่ที่จะบอกว่า เมื่อ terraform ทำงานเสร็จเรียบร้อย จะจัดเก็บ terraform state ไว้ด้วยวิธีการอะไร ซึ่งโดยปกติ terraform จะเรียกใช้งาน backend ที่ชื่อว่า local ซึ่งก็จะเป็นการจัดเก็บในรูปแบบของไฟล์ไว้ที่ working directory

Backend เก็บที่ไหนได้บ้าง

  • local
  • azurerm - Azure Blob Storage
  • consul - Consul KV store
  • cos - Tencent Cloud Object Storage
  • gcs - Google Cloud Storage
  • http - simple REST client
  • kubernetes - Kubernetes secret
  • oss - Alibaba Cloud OSS
  • pg - Postgres database
  • s3 - Amazon S3

ทดลองเก็บไว้ที่ postgres

ลองหยิบ postgres database มาศึกษาดูแนวคิดในการใช้ backend เพื่อเก็บ terraform state ซึ่งหาข้อมูลได้จาก postgres backend

  1. สร้าง postgres database server ในกรณีนี้จะใช้ container technology เป็นไว้ที่ server ชื่อว่า tfstate.d8k.dev และกำหนดให้ postgres database ทำงานที่ port TCP/5433
    
    $ mkdir tfstate
    $ cd tfstate
    $ cat > docker-compose.yaml <<- EOF
    services:
      db:
        image: postgres
        restart: always
        ports:
          - 5433:5432
        environment:
          POSTGRES_USER: tf
          POSTGRES_PASSWORD: mypsddeotf
          POSTGRES_DB: tf_backend
    EOF
    
    $  docker-compose up -d
    Creating network "tfstate_default" with the default driver
    Creating tfstate_db_1 ... done
    
  2. สร้าง terraform configuration file เพื่อทำการทดสอบ โดยเลือกให้ใช้ provider ที่ชื่อว่า kreuzwerker/docker โดยจะให้สร้าง container 1 ตัวชื่อว่า myapp
    ส่วนสำคัญที่จะกำหนดให้ Terraform ไปเรียกใช้ backend ที่เป็น postgres จะอยู่ภายใน terraform block ตรงที่ระบุว่าเป็น backend เป็น pg และระบุรายละเอียดของ backend ผ่านตัวแปรที่ชื่อว่า conn_str
    
    
    terraform {
      backend "pg" {
        conn_str = "postgres://tf:mypsddeotf@tfstate.d8k.dev:5433/tf_backend?sslmode=disable"
      }
    }  
    
    หมายเหตุ: เครื่องที่ใช้ในการทดสอบ ต้องติดตั้ง terraform และมี Docker ทำงานอยู่เรียบร้อยแล้ว

    
    $ mkdir tf-docker
    $ cd tf-docker
    $ cat > main.tf <<EOF
    terraform {
      backend "pg" {
        conn_str = "postgres://tf:mypsddeotf@tfstate.d8k.dev:5433/tf_backend?sslmode=disable"
      }
      required_providers {
        docker = {
          source  = "kreuzwerker/docker"
        }
      }
    }
    
    provider "docker" {
      host = "unix:///var/run/docker.sock"
    }
    
    resource "docker_image" "nginx" {
      name = "nginx"
    }
    
    resource "docker_container" "myapp" {
      name  = "myapp"
      image = docker_image.nginx.image_id
    }
    $ terraform init
    
    Initializing the backend...
    
    Successfully configured the backend "pg"! Terraform will automatically
    use this backend unless the backend configuration changes.
    
    Initializing provider plugins...
    - Finding kreuzwerker/docker versions matching "3.0.2"...
    - Installing kreuzwerker/docker v3.0.2...
    - Installed kreuzwerker/docker v3.0.2 (self-signed, key ID BD080C4571C6104C)
    [... truncated output ...]
    
    EOF
    ## - ยืนยันว่ายังไม่มี container ที่ชื่อว่า myapp
    $ docker container ls -a | grep myapp
    
    $ terraform apply --auto-approve
    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:
    
      # docker_container.myapp will be created
      + resource "docker_container" "myapp" {
    
    [... truncated output ...]
    
    $ docker container ls  | grep myapp
    28a46551b1a3   2a4fbb36e966    "/docker-entrypoint.…"   43 seconds ago   Up 43 seconds   80/tcp                              myapp
    
    ## - ไม่พบไฟล์ terraform state
    $ ls -la terraform.tfstate
    ls: terraform.tfstate: No such file or directory
    
    ## - คำสั่งแสดงข้อมูล terraform state พบว่ามี resource อยู่ 2 ตัวตามที่ระบุไว้ใน main.tf
    $ terraform state list
    docker_container.myapp
    docker_image.nginx
    
  3. ทดลอง สร้าง working directory ที่ 2 โดยใช้ main.tf ตัวเดิม และให้แสดงค่า terraform state จะพบว่า ใน working directory ที่ 2 ก็จะมีข้อมูล terraform state อยู่เช่นเดียวกัน
    
    $ mkdir test
    $ cp main.tf ./test
    $ terraform init
    
    Initializing the backend...
    
    Initializing provider plugins...
    - Reusing previous version of kreuzwerker/docker from the dependency lock file
    - Using previously-installed kreuzwerker/docker v3.0.2
    
    Terraform has been successfully initialized!
    [... truncated output ...]
    
    $ terraform state list
    docker_container.myapp
    docker_image.nginx
    
    

cover

Share on

Tags

Human knowledge belongs to the world

a line from the movie "Antitrust"