用 Terraform 建立 VS Code Server

程式技術
sharkHead
用 Terraform 建立 VS Code Server

前幾週,我看到 VS Code 的 YouTube 頻道發布了一個新的影片。

哇喔,Use VS Code ANYWHERE是有沒有這麼肝?

VS  Code 之前推出過 vscode.dev,讓你可以在瀏覽器上使用 VS Code 開啟 GitHub Repo 來寫程式,但因為只是單純在瀏覽器上開啟 Repo,所以不只沒有開發環境可以使用,VS Code 的套件也只有支援一部分。

VS Code Server 則提供另外一種選擇,只要架好一台 Server,並在上面安裝好 VS Code Server,就可以透過瀏覽器遠端連上 Server,除了具備開發環境,也能使用大部分的 VS Code 套件。

本篇文章會簡單介紹,如何使用 Terraform 在 AWS 上建立一台 Ubuntu 22.04 的 EC2 Instance (虛擬主機),並設置好 VPC 與 Public IP。然後在 Server上安裝 VS Code Server,讓我們透過瀏覽器以 SSL 的方式連上 EC2 Instance。

 安裝 Terraform 與設定 AWS IAM Key

請先安裝 Terraform,如果是 Mac 的用戶可以直接使用 Homebrew 安裝。

brew install terraform

其他平台的安裝方式可以參考 Terraform 官方文件 - Install Terraform

安裝好之後可以使用指令查看 Terraform 是否安裝成功。

terraform version

指令中 terraform 這個詞的單字有點多,建議可以設定別名 (alias)。

alias tf="terraform"

因為 Terraform 會使用 AWS 的 Provider 來建立 EC2 Instance,所以除了需要註冊一個 AWS 的帳號之外,還需要透過 IAM 建立一組 Administrator 的 Key 來給 Terraform 使用。

IAM Key 的建立可以參考 AWS 官方文件 - 在您的 AWS 帳戶中建立 IAM 使用者

當建立好 Key 後,可以透過 AWS CLI 的在本地環境設定 IAM 的 Key。

# 之後依序輸入 Access key、Secret Key 與 Region 就可以設定完成
aws configure

除了 AWS CLI ,你也可以透過環境變數的方式來設定 IAM 的 Key。

export AWS_ACCESS_KEY_ID="anaccesskey"
export AWS_SECRET_ACCESS_KEY="asecretkey"
export AWS_REGION="us-west-2"

 使用 Terraform 建立 EC2 Instance

建立一個 code-server 資料夾,接下來所有的 Terraform 檔案都會存放在這個資料夾中。

首先新增一個 main.tf 檔案。

# 這裡可以說明要使用 AWS Provider
# 因為 Key 與 Region 都已在環境中設定好,因此這裡不需要放入任何內容 (也不建議用 Hardcode 的方式設定 Key)
# 直接刪除這段也沒有問題
provider "aws" {
  region = "ap-northeast-2"
  # access_key = "my-access-key"
  # secret_key = "my-secret-key"
}

# 在多人協作,Terraform 的 Best Practice 建議使用 State Lock 與 Remote State
# 這段刪除沒有任何影響,僅僅代表不使用 State Lock 與使用 Local State
terraform {
  # ref: <https://www.terraform.io/language/settings/backends/s3>
  backend "s3" {
    bucket         = "terraform-state-archives"
    key            = "vs-code-server-terraform.tfstate"
    region         = "ap-northeast-2"
    dynamodb_table = "vs-code-state-locking"
  }
}

新增一個 variables.tf 檔案,設定用來連上 EC2 Instance 的 Key Pair。

# 可以使用指令 ssh-keygen 產出 public key 與 private key
variable "public_key" {
  default = "這裡貼上你的 ssh public key"
}

新增一個 vpc.tf 檔案,設定 VPC、Internet Gateway、Subnet 與 Route Table。

# 設定虛擬私有雲端 (Virtual Private Cloud, VPC)
resource "aws_vpc" "code_server_vpc" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true
}

# 設定網際網路閘道,讓 VPC 中的執行個體可以與外部網際網路之間進行通訊
resource "aws_internet_gateway" "code_server_gateway" {
  vpc_id = aws_vpc.code_server_vpc.id
}

# 建立子網路,EC2 instance 會放在此子網路中
resource "aws_subnet" "code_server_subnet" {
  vpc_id = aws_vpc.code_server_vpc.id
  # Subnet 需要與 Instance 的 Availability Zone 相同
  availability_zone = data.aws_availability_zones.available.names[0]
  cidr_block        = "10.0.0.0/24"
}

# 設定路由表,用來決定 subnet 中的流量要導向哪裡
# 這裡設定如果要連外部網路,就將流量導向 internet gateway
resource "aws_route_table" "code_server_route_table" {
  vpc_id = aws_vpc.code_server_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.code_server_gateway.id
  }
}

resource "aws_route_table_association" "subnet-association" {
  subnet_id      = aws_subnet.code_server_subnet.id
  route_table_id = aws_route_table.code_server_route_table.id
}

# 設定 EC2 instance 的 public IP
resource "aws_eip" "code_server_public_ip" {
  instance = aws_instance.code_server.id
  vpc      = true
}

新增一個 ec2.tf 檔案,並設定 EC2 Instance。

# Instance Type 在各地區都有對應的 Availability Zone
# 這裡透過 aws_availability_zones 過濾出可以使用的 Availability Zone
# ref: https://aws.amazon.com/tw/premiumsupport/knowledge-center/ec2-instance-type-not-supported-az-error/
data "aws_availability_zones" "available" {
  state = "available"
}

resource "aws_instance" "code_server" {
  # ubuntu 22.04 ARM 的 AMI (Amazon Machine Image)
  ami = "ami-04c65fa50a4122444"
  # 使用 Amazom 自家 ARM CPU 的 Server,費用會比較便宜
  instance_type = "t4g.small"
  # 設定遠端連上 instance 的 key pair
  key_name        = aws_key_pair.code_server_key_pair.key_name
  security_groups = [aws_security_group.code_server_security_group.id]
  availability_zone = data.aws_availability_zones.available.names[0]
  # Instance Type 在各地區都有對應的 Availability Zone,這裡需要特別註明要使用哪個 Availability Zone
  # ref: https://aws.amazon.com/tw/premiumsupport/knowledge-center/ec2-instance-type-not-supported-az-error/
  availability_zone = "ap-northeast-2b"

  tags = {
    Name = "code_server"
  }

  # 設定 instance 的容量 (Elatic Block Storage, EBS)
  ebs_block_device {
    device_name = "/dev/sda1"
    volume_size = 20
  }

  # 將 intance 放入指定的子網路中
  subnet_id = aws_subnet.code_server_subnet.id
}

# 設定 security groups,用途類似於防火牆,可以用來決定 inbound 與 outbound 的規則
resource "aws_security_group" "code_server_security_group" {
  name   = "code_server"
  vpc_id = aws_vpc.code_server_vpc.id

  ingress {
    description = "SSH"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

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

  ingress {
    description = "HTTPS"
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

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

# 設定用來連線 instance 的 key pair
resource "aws_key_pair" "code_server_key_pair" {
  key_name = "code_server"
  # 剛剛在 variables.tf 中設定的 public key
  public_key = var.public_key
}

建立一個 outputs.tf 檔案,用來在 Console 畫面上印出  EC2 Instance 的 Public IP。

# 印出 instance 的 public IP
output "instance_public_ip" {
  description = "Public IP address of the EC2 instance"
  value       = aws_eip.code_server_public_ip.public_ip
}


# 印出 Availability Zone
output "availability_zones" {
  description = "Availability zones of Subnet and EC2 instance"
  value       = data.aws_availability_zones.available.names[0]
}

設定好之後就可以使用 terraform plan 指令查看部署計畫的內容有沒有問題。

terraform plan

當部署計畫的內容確定沒問題之後,就可以使用 terraform apply 指令開始進行部署。

terraform apply

部署結束之後,應該可以看到  Console 畫面上有印出 EC2 Instance 的 Public IP,這時可以使用 SSH 指令連線看看。

ssh -i "private key file path" ubuntu@"你的 Instance Public IP"

如果可以連上的話,就代表虛擬主機已經成功建立起來了。

 安裝 VS Code Server

使用 SSH 連線至 EC2 Instance,然後就是 Ubuntu 起手式,更新套件。

sudo apt update && sudo apt upgrade

然後根據官方文件的安裝方式,執行官方的安裝 Shell Script。

curl -fsSL https://code-server.dev/install.sh | sh

安裝完畢之後就可以啟動 VS Code Server。

sudo systemctl start code-server@$USER

也可以設定在開機自動啟動 VS Code Server。

sudo systemctl enable --now code-server@$USER

VS Code Server 預設是使用 8080 Port,在剛剛的 ec2.tf 的 Security Group 中,我們並沒有設定 8080 Port,因此打開瀏覽器訪問網址 http://your-instatnce-public-ip:8080 也無法連上 VS Code Server。

這時我們可以安裝 Nginx 啟動一個 Web Server,再將 80 Port 的流量轉到 8080 Port。

安裝 Nginx。

sudo apt install nginx -y

/etc/nginx/sites-available/ 底下新增一個 code-server 設定檔案。

server {
    listen 80;
    listen [::]:80;
    server_name ~^.*$;

    location / {
        proxy_pass http://localhost:8080/;
        proxy_set_header Host $host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection upgrade;
        proxy_set_header Accept-Encoding gzip;
    }
}

啟動這個 Nginx 設定檔案。

sudo ln -s /etc/nginx/sites-available/code-server /etc/nginx/sites-enabled/code-server

重新啟動 Nginx。

sudo systemctl restart nginx

這時重新打開瀏覽器輸入網址 http://your-instatnce-public-ip:8080,看到以下畫面就代表成功訪問 VS Code Server。

2022_08_02_17_21_24_62e8ec946a0e7.png

VS Code Server 的密碼設定會存放在 ~/.config/code-server/config.yaml,你可以更改此檔案中的密碼並重新啟動 VS Code Server。

bind-addr: 127.0.0.1:8080
auth: password
password: VS Code Server 密碼
cert: false

輸入密碼之後,就可以看到熟悉的 VS Code 畫面了,不只有開發環境可以使用,VS Code 套件也幾乎都支援。

2022_08_02_17_22_17_62e8ecc9cb5cd.png

VS Code Server 幾點觀察

  • VS Code Server 會在網址中帶一個 Query string 參數 folder,用來設定要開啟的資料夾路徑,所以想切換資料夾的話可以在網址中修改 folder 的參數。
  • 目前還不支援 VS Code 設定同步的功能,稍微有些可惜,但可以自行設定開發環境確實很方便。
  • 建議買個 Domain 設定 SSL,畢竟未加密的傳輸,即使有設定密碼也無濟於事。

接下來最重要的步驟!

使用 Terrform 刪除剛剛部署的所有 AWS 資源

terraform destroy

🙂!?

只有 2 CPU 與 2 GB Memory 的虛擬主機,一個月的費用大約 15 美金,這太不吸引我了 🤪。除非有一定要在 iPad 上面寫程式的需求。否則還是在自己電腦上開發吧。

如果真的要使用 VS Code Server,建議自己組一台效能不錯的電腦放在家中,再跟電信商申請固定 IP 來設定連線,使用舒適度應該會高上許多。

前輩:用 SSH 上去安裝太 LOW 了,考慮用 User Data 吧。 👍

參考資料

sharkHead
written by
sharkHead

後端打工仔,在下班後喜歡研究各種不同的技術。稍微擅長 PHP,並偶爾涉獵前端開發。個性就像動態語言般隨興,但渴望做事能像囉嗦的靜態語言那樣嚴謹。

0 則留言