2020年9月26日 星期六

使用 Terraform 佈署在 AWS Lightsail 上的 Instance ,並在遠端執行自訂安裝 shell

使用 Terraform 好處是,可以直接把公司內部的基礎建設做好配置或是標準,使得要開始建立雲端資源時,可以確保每次建立出來的服務、VPC、Instance、ClodPlatform 設定檔都一致,這篇文章示範如何使用 Terraform 去佈署 AWS Lightsail ,然後想要在建立 Instance 後, 連進去做某些事。


必備安裝


Terraform 是在【本地電腦】中,去代替你執行各大 Platform 亦或是 Docker 等 Deploy 相關指令,因此,本篇文章要佈署的目的是 AWS Lightsail,所以需要安裝 AWS-CLI ,而且,要完成 AWS-CLI 設定:

aws configure


這個 AWS Access Key ID 跟 AWS Secret Access ,你需要去 AWS Platform 上新增 IAM 並賦予使用者操作 Lightsail 權限,才可以使用下去。


用 Terraform 腳本


Terraform 腳本寫好後,依序是【先安裝必要的 Model】、再做資料驗證、最後再佈署上去,到著從目的看,其實不同的雲端,就代表是不同的 provider,以下是 main.tf 檔案寫法:

terraform {
  required_providers { #定義提供者
    aws = {
      source  = "hashicorp/aws" #引用該 model
      version = "~> 2.70"
    }
  }
}

provider "aws" { #定義服務提供者
  region = "ap-northeast-1" #定義要用哪個 region
}


# Create a new Lightsail Instance
#resource "服務提供者的服務名稱" "自訂執行區塊名稱"
resource "aws_lightsail_instance" "app" {
  name              = "HELLO.MYAPP"        #[NAME].[DOMAIN] 
  availability_zone = "ap-northeast-1a"    #instance 開啟的區域 (東京 1a)
  blueprint_id      = "centos_7_1901_01"   #instance 開啟的 OS 或服務 (E.g: wordpress)
  bundle_id         = "nano_2_0"           #instance 放案類型
}

關於上面的設定,我該填上什麼值,請參考 Terraform - lightsail_instance 


Terraform 執行指令


執行指令,依序步驟是:

  1. terraform init (初始化,安裝必要的 model)
  2. terraform fmt (格式化)
  3. terraform validate (驗證你寫的東西有沒有問題)
  4. terraform apply (真實的佈署到你的 aws)
  5. terraform destroy (毀滅你剛才佈署到 aws 的東西)


用 Terraform 打開機器後,在裡面傳檔案執行指令


雖然是開了機器,但我想要把 shell 檔案傳上去,預先安裝甚麼東西的話,可以怎麼做?

首先,必備項目是,去 Lightsail 取得你的連線專用 pem key (以下腳本中,用的是我下載的檔案: LightsailDefaultKey-ap-northeast-1.pem) ,下載後跟 main.tf 放在一起 (注意最好不要放到甚麼公開資料夾,這可是你的 private key)。



然後,目的是希望產生 instance 後,可以自動執行某檔案的指令,所以,希望等等可以執行 setup.sh 這個檔案,首先,先寫好 main.tf:

terraform { #定義 init
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 2.70"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

#綁住 instance_name 跟 static_ip 的關係,也就是,當下面那個 resource (aws_lightsail_static_ip) 產生之後,
#要求跟指定的 instance_name 綁定,這樣靜態 IP 就會綁在該 instance。
resource "aws_lightsail_static_ip_attachment" "app" { 
  static_ip_name = aws_lightsail_static_ip.app.name
  instance_name  = aws_lightsail_instance.app.name
}

#取得 lightsail 一產生 instance 後的靜態 IP 位置,用於等一下要連進去
#也用於等一下要綁定 IP 到 instance
resource "aws_lightsail_static_ip" "app" {
  name = "HELLO" #name
}

# Create a new Lightsail Instance
resource "aws_lightsail_instance" "app" {
  name              = "HEELLO.MYAPP" #name.domain
  availability_zone = "ap-northeast-1a"
  blueprint_id      = "centos_7_1901_01"
  bundle_id         = "nano_2_0"
}

# 定義無服務提供者,是自己
resource "null_resource" "app" {
  triggers = { #該服務觸發器,是等到 static_ip 取得後。
    public_ip = aws_lightsail_static_ip.app.ip_address
  }

  # 開啟連線事件,要準備連上 lightsail 的 instance
  connection {
    type  = "ssh"
    host  = aws_lightsail_static_ip.app.ip_address
    user  = "centos" #這 aws 有寫你欲設的 user 會是啥名字, 開 ubuntu 就叫 ubuntu
    private_key = "${file("./LightsailDefaultKey-ap-northeast-1.pem")}"
    timeout     = "2m"
  }
	
  # 要複製過去的檔案
  // copy our example script to the server
  provisioner "file" {
    source      = "setup.sh"
    destination = "/tmp/setup.sh"
  }
  
  # 要在遠端執行的命令
  // change permissions to executable and pipe its output into a new file
  provisioner "remote-exec" {
    inline = [
      "chmod +x /tmp/setup.sh",
      "/tmp/setup.sh > /tmp/setup.log",
    ]
  }

}


再來,要處理 setup.sh 這個檔案,我們希望他可以預設幫我們先安裝好 Node.js 12.x 跟先建立好資料庫:


#! /bin/bash
# 注意檔案 CR 問題,會導致 file format 不是 unix
# init script:

# init sql
sudo yum -y update
sudo yum -y install mariadb-server
sudo systemctl enable mariadb
sudo systemctl start mariadb
systemctl status mariadb

# 安裝 mysql https://gist.github.com/vdvm/24754bf1aee6fd85e1aa
echo "正在安裝 mysql_secure_installition, 密碼: [PASSWORD] (請自行覆蓋)"
echo -e "\n\n[PASSWORD]\n[PASSWORD]\n\n\nn\n\n " | mysql_secure_installation 2>/dev/null
# 安裝 SQL 資料庫 echo "正在建立資料庫: [db_name]" mysql -u root -p'[PASSWORD]' -h localhost -P 3306 -e "CREATE DATABASE [db_name];"
# 安裝 SQL 表 echo "== 請自行手動安裝 SQL 表。" # init port echo "開啟防火牆 80 port" sudo yum install -y firewalld sudo firewall-cmd --zone=public --add-port=80/tcp --permanent sudo firewall-cmd --zone=public --add-port=22/tcp --permanent sudo firewall-cmd --reload # node.js install sudo yum install -y gcc-c++ make echo "如果 nodesource 找不到東西,可以嘗試改北清大 mirror" curl -sL https://rpm.nodesource.com/setup_12.x | sudo bash - sudo yum install -y nodejs sudo npm config set registry http://registry.npmjs.org/ sudo npm config set strict-ssl false # deploy script sudo npm install pm2 -g # CI/CD KEY (/tmp/sshkey.pub) ssh-keygen -b 2048 -t rsa -f /tmp/sshkey -q -N ""

注意,上述腳本註解有提到 Sehll CR 轉換問題,如果你這個 setup.sh 是在 windows 上寫的,很可能會在 Linux 上無法被執行腳本,是因為檔案的斷行模式問題,如果是在 windows 寫的用戶,最好是在 WSL 中,用 vim 打開這個檔案,然後使用轉換指令:


  • :set fileformat=unix
  • :wq!


完成後,直接執行 terraform apply,需要等待一陣子,就可以看到 Instance 自動被建立,直接進去也裝好 Node.js 了。


Reference:

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lightsail_instance
https://www.terraform.io/
https://stackoverflow.com/questions/2920416/configure-bin-shm-bad-interpreter
https://medium.com/@chihsuan/terraform-%E8%87%AA%E5%8B%95%E5%8C%96%E7%9A%84%E5%9F%BA%E7%A4%8E%E6%9E%B6%E6%A7%8B%E4%BB%8B%E7%B4%B9-f827e8975e98

沒有留言:

張貼留言

© Mac Taylor, 歡迎自由轉貼。
Background Email Pattern by Toby Elliott
Since 2014