iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 11
1
DevOps

今晚我想來點 Terraform 佐 AWS系列 第 11

今晚我想佈建一台網頁伺服器

  • 分享至 

  • xImage
  •  

參考了前面文章的介紹的功能,我們要試著讓組態檔更有可用性。

今天來試著製作一台網頁伺服器。

簡單的網頁伺服器

一台簡單的網頁伺服器需要的工作:

  1. 建立一個虛擬網路
  2. 切出一個網段
  3. 開啟一個虛擬機
  4. 放到 SSH 公鑰
  5. 設定防火牆
  6. 安裝 nginx 做為網頁服務引擎

要安裝 nginx,的方法有很多,可以登入伺服器,下指令安裝。但是這樣不符合,IaC 的精神。

我們來試試 Terraform 的佈建器 (provisioner)

佈建器 (provisioner)

用佈建器來完成在伺服器上安裝 nginx 這件工作。我們會用到兩個區塊,connctionprovisioner 區塊,兩個都要放在 aws_instance 裡面。

首先是 connection 區塊,常用的引數 (Arguments) 有:

  • type: 支援 sshwinrm
  • user: 建立連線所使用的使用者
  • host: 伺服器的 IP
  • private_key: ssh 私鑰

再來是 provisioner 區塊,有分 file, local-execremote-exec 三種。

我們要在伺服器執行一些指令,使用的是 remote-exec,主要的引數:

  • inline: 指令清單

完整範例

把輸入變數 (Input Variables) 跟輸出值 (Output Values) 加入組態檔,並使用佈建器 (provisioner) 來安裝服務。

完成的檔案清單:

  • variables.tf
  • main.tf
  • outputs.tf
  • terraform.tfvars

variables.tf

variable "aws_region" {
  type        = string
  description = "AWS region to launch servers."
  default     = "ap-northeast-1"
}

variable "cidr" {
  type        = string
  description = "vpc cidr block"
}

variable "public_subnet" {
  type        = string
  description = "public subnet cidr block"
}

variable "public_key_path" {
  type        = string
  description = "Path to SSH public key"
  default     = "~/.ssh/id_rsa.pub"
}

variable "private_key_path" {
  type        = string
  description = "Path to SSH private key"
  default     = "~/.ssh/id_rsa"
}

variable "ami" {
  type        = string
  description = "ami id"
}

variable "my_ip" {
  type        = string
  description = "my ip to allow ssh connection"
}

main.tf

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "3.5.0"
    }
  }
}

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

resource "aws_vpc" "this" {
  cidr_block = var.cidr
}

resource "aws_internet_gateway" "this" {
  vpc_id = aws_vpc.this.id
}

resource "aws_route" "internet_access" {
  route_table_id         = aws_vpc.this.main_route_table_id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = aws_internet_gateway.this.id
}

resource "aws_subnet" "this" {
  vpc_id                  = aws_vpc.this.id
  cidr_block              = var.public_subnet
  map_public_ip_on_launch = true
}

resource "aws_security_group" "ssh" {
  name        = "ssh"
  description = "sg for ssh incoming"
  vpc_id      = aws_vpc.this.id

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = [format("%s/32", var.my_ip)]
  }
}

resource "aws_security_group" "web" {
  name        = "web"
  description = "sg for web incoming"
  vpc_id      = aws_vpc.this.id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # outbound internet access
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_key_pair" "practice" {
  key_name   = "practice"
  public_key = file(var.public_key_path)
}

resource "aws_instance" "web" {
  ami           = var.ami
  instance_type = "t2.micro"

  key_name = aws_key_pair.practice.id

  vpc_security_group_ids = [
    aws_security_group.ssh.id,
    aws_security_group.web.id,
  ]

  subnet_id = aws_subnet.this.id

  connection {
    type        = "ssh"
    user        = "ubuntu"
    host        = self.public_ip
    private_key = file(var.private_key_path)
  }

  provisioner "remote-exec" {
    inline = [
      "sudo apt-get update",
      "sudo apt-get install -y nginx",
    ]
  }
}

output.tf

output "vpc_id" {
  description = "ID of VPC"
  value       = aws_vpc.this.id
}

output "web_instance_id" {
  description = "ID of web instance"
  value       = aws_instance.web.id
}

output "web_public_ip" {
  description = "Public IP of web server"
  value       = aws_instance.web.public_ip
}

terraform.tfvars

cidr            = "10.0.0.0/16"
public_subnet   = "10.0.1.0/24"
public_key_path = "~/.ssh/id_rsa.pub"

# Ubuntu Server 20.04 LTS (HVM), SSD Volume Type, 64-bit x86
ami = "ami-0461b11e2fad8c14a"

執行

先查詢你目前的 public ip,接著執行 apply 指令並帶入變數

$ terraform apply -var="my_ip=xxx.xxx.xxx.xxx"

...

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

Outputs:

vpc_id = vpc-03fa104e06a386d5d
web_instance_id = i-02726dce6cb801181
web_public_ip = 123.123.123.123

完成了就可以開啟 http://123.123.123.123 驗收一下網頁服務。

佈建器 (provisioner) 這個方法並不是 Terraform 推薦的方法,在測試的過程中我有遇到幾次的失敗。

後面我們再找其他的辦法來試試。


上一篇
今晚我想「輸出」狀態檔的重點
下一篇
今晚我想打開神秘的使用者資料
系列文
今晚我想來點 Terraform 佐 AWS30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言