1. 実行環境
- Windows10
- git for windows(必須ではないが、Windows上でbashなどを使うため)
- Terraform v0.14.3
- awscli(2.1.14)
前提条件として、aws configure
を予め実行しておくなどして、自身のaws環境にawsコマンドでアクセスできるようにしておく。
また、今回terraformとawscliはscoopでインストールしている。
scoop install aws terraform
scoopのインストールは例えば
https://scoop.sh/ (公式)
https://qiita.com/Dooteeen/items/12dc8fb14042888113d0
などを参照
2. 実行
2-1. 必要ファイルの作成
適当なディレクトリに以下のファイルを作成、配置
$ tree
.
├── main.tf # terraformファイル
├── provision.sh # provisioning用スクリプト
└── set_env # 環境変数設定、必須ではないが便利のため
各ファイルの詳細:
2-1-1. main.tf
# 実行環境ごとに変わるものや秘匿したい情報は変数化出来る
variable "key_name" {}
variable "public_key_path" {}
variable "private_key_path" {}
provider "aws" {
profile = "default"
region = "ap-northeast-1"
}
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
owners = ["099720109477"] # Canonical
}
resource "aws_instance" "example" {
ami = data.aws_ami.ubuntu.id
instance_type = "t3a.small"
key_name = aws_key_pair.deployer.id
associate_public_ip_address = true
vpc_security_group_ids = ["${aws_security_group.default.id}"]
tags = {
Name = "terraform-ubuntu-mate-test1"
}
provisioner "file" {
source = "provision.sh"
destination = "/tmp/provision.sh"
connection {
type = "ssh"
host = self.public_ip
user = "ubuntu"
private_key = file(var.private_key_path)
}
}
provisioner "remote-exec" {
inline = [
"chmod +x /tmp/provision.sh",
"/tmp/provision.sh",
]
connection {
type = "ssh"
host = self.public_ip
user = "ubuntu"
private_key = file(var.private_key_path)
}
}
}
resource "aws_key_pair" "deployer" {
key_name = var.key_name
public_key = file(var.public_key_path)
}
resource "aws_security_group" "default" {
name = "ssh_default_security_group"
description = "ssh default"
# SSH access from anywhere
ingress {
from_port = 22
to_port = 22
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"]
}
}
main.tf
作成における主な参考リンク:
- Ubuntu20.04のAMIイメージの利用
- tagの利用(立ち上げるEC2インスタンスに"terraform-ubuntu-mate-test1"という名前をつけている)
- 変数の使用(実行環境に依存性のある値や秘匿すべき情報などを外部から与える)
- EC2へsshでアクセスするためのキーペアの作成・管理
- セキュリティグループの作成・管理
-
https://dev.classmethod.jp/articles/my-mistake-about-creating-sg-by-terraform/
- アウトバウンドは全部許可、インバウンドは22ポートによるsshのみ許可
-
https://dev.classmethod.jp/articles/my-mistake-about-creating-sg-by-terraform/
- provisioningのスクリプトのアップロードと実行
秘密鍵・公開鍵関係の情報は外部変数として宣言しておき、環境変数TF_VAR_**
を設定することでterraform側に渡すようにしている。(後でsource set_env
して読み込む)
また、ubuntuのprovisioningはprovision.sh
という別のスクリプトファイルにしておき、ローカルからEC2側へアップロード・実行させている。
(AWSのWebコンソール上からEC2を普通に作るのと比べると、はじめは一つ一つ記述しないといけないため思った以上に面倒だった。。。)
注意点として、デスクトップ環境構築のためにインスタンスタイプはt3a.small
タイプを指定しているため無料枠の対象外となっている。(t3a.small
にあまり深い意味は無いが、t2.micro
のメモリ1GBでは流石にスペックが足りないため)
2-1-2. provision.sh
#!/usr/bin/env sh
set -eux
# クラウド側のセットアップ完了を待たないとapt-get等が失敗する
while [ ! -f /var/lib/cloud/instance/boot-finished ]; do
sleep 1
done
sudo apt-get update
# mate-desktop
sudo apt-get -y install \
mate-desktop \
mate-desktop-environment \
mate-desktop-environment-extra \
mate-session-manager
# xrdp
sudo apt-get install -y xrdp
sudo sed -e 's/^new_cursors=true/new_cursors=false/g' \
-i /etc/xrdp/xrdp.ini
sudo service xrdp start
# xrdp xsession
echo "mate-session" > ~/.xsession
XDG_DATA_DIRS=/usr/share/mate:/usr/share/mate:/usr/local/share
XDG_DATA_DIRS=${XDG_DATA_DIRS}:/usr/share:/var/lib/snapd/desktop
cat <<EOF > ~/.xsessionrc
export XDG_SESSION_DESKTOP=mate
export XDG_DATA_DIRS=${XDG_DATA_DIRS}
export XDG_CONFIG_DIRS=/etc/xdg/xdg-mate:/etc/xdg
EOF
# set password
sudo USER_PASSWD=${USER_PASSWD:-changeit} sh -c '
echo "${USER_PASSWD}\n${USER_PASSWD}" | passwd ubuntu
'
echo "Done: $(basename $0)"
mate-desktopのセットアップは大まかに
https://www.hiroom2.com/2018/05/06/ubuntu-1804-mate-ja/
https://www.hiroom2.com/2018/05/07/ubuntu-1804-xrdp-mate-ja/
を参考にして、xrdp
によってリモートデスクトップを使えるようにしている。
特に詰まったポイントは、
while [ ! -f /var/lib/cloud/instance/boot-finished ]; do
sleep 1
done
の部分。
どうやら「provisioningが始まるタイミング=クラウド側の環境の準備完了」ではないらしく、この部分を入れないとapt-get update
でリポジトリ情報が更新されず、その結果apt-get install
でエラーが起こってしまう。
(参考: https://stackoverflow.com/questions/42279763/why-does-terraform-apt-get-fail-intermittently )
ここで、ログインユーザーはデフォルトで用意されているubuntu
にしており、ログインパスワードはとりあえずchangeit
でハードコードしていることに注意。
2-1-3. set_env
先述のterraformファイルで外部変数を使用するために必要な環境変数を設定:
export TF_VAR_key_name=key_terraform
export TF_VAR_public_key_path="${HOME}/.ssh/key_terraform.pub"
export TF_VAR_private_key_path="${HOME}/.ssh/key_terraform"
上記の内容は適宜書き換えを行う。また、また、該当するパスに秘密鍵と公開鍵を予め作っておく。上記の例であれば、
ssh-keygen -t rsa -b 4096 -f $HOME/.ssh/key_terraform # 4096bitのRSA, ファイル名と置き場所も指定しておく
のようにすればOK
(terraformを実行するとAWS環境にアップロードされて、自動でキーペアが作成・管理されるようになる)
なお、今回はgit for windowsに付属のbash(msys2)を使っており、linuxと同様のやり方で動くようにしている。
(コマンドプロンプトなどを使う場合は少しやり方を変える必要)
2-2. ec2の起動とrdp接続
2-1. で作ったファイルを置いたディレクトリ上でgit bashを立ち上げ、以下を実行すると起動
# 環境変数の設定(※パスした場合は、対話形式で変数を設定することも可能)
source set_env
# ディレクトリを初期化
terraform init
# awsリソースの起動
terraform apply # 問題無いか聞かれるので、確認してOKなら`yes`を入力してEnterを押すとスタートする
provisioningには20~30分オーダーで時間がかかる。
無事完了した後は、
terraform show
で立ち上がったリソースの情報を確認出来るので、そこからpublic_id
かpublic_dns
を調べる(ssh接続に必要。他にはAWSコンソールのEC2ダッシュボード等からも確認出来るのでそれでもOK)
次に立ち上がったEC2へのリモートデスクトップ接続を行う。
今回はセキュリティを考えてEC2はssh用のポート(22)のみを開放しているため、ポートフォワードを行う必要がある。
そこで、git bash上で下記のようにssh接続を行う:
ssh -i ~/.ssh/key_terraform ubuntu@ec2-XX-XX-XX-XX.ap-northeast-1.compute.amazonaws.com -L 13389:localhost:3389
-
-i
オプションで使用する秘密鍵を指定している(実際に使っているものに合わせて適宜書き換え) -
ubuntu@***
の***
部分には上記で調べたEC2のIPアドレスかURL(public_id
ないしpublic_dns
部分)を入れる -
-L
オプションでポートフォワードを行っており、ここではEC2側の3389ポート(リモートデスクトップ用のxrdp
で使用)をローカル端末の13389ポートに転送している(ここも使用状況に合わせて適宜書き換え)
ここで、ウィンドウズキーを押してrdp
と入力して検索を行うと「リモートデスクトップ接続」を選択出来るので、Enterを押して選択し、「コンピュータ名」にlocalhost:13389
を入力して「接続」を押す。
以下の画面が出てきたらusernameにubuntu
、passwordにprovision.sh
で設定したパスワードを入力してOKを押す。
以下のような画面が出てくればOK
実行にはお金がかかるので、使わないときはAWSコンソールからインスタンスを停止したり、
削除するときは
terraform destroy # 消してOKか聞かれるので、確認してからyesを入力
によって関連するAWSリソースをひとまとめに削除出来る
(参考)日本語環境
上記までだと日本語用の設定が行われていないので、必要に応じてprovisioningの段階で設定を行う
例えば、以下のような内容をprovision.sh
に追記することで、日本語用パッケージ(IMEなど)のインストールやタイムゾーン・local設定などを行える:
apt install -y \
language-pack-ja-base language-pack-ja \
ibus-kkc ibus-mozc
# ubuntu-defaults-ja バージョンに応じて適切なものを選択・インストール
UBUNTU_VERSION=$(. /etc/lsb-release; echo $DISTRIB_RELEASE)
UBUNTU_CODENAME=$(. /etc/lsb-release; echo $DISTRIB_CODENAME)
if [ $UBUNTU_VERSION = "20.10" ]; then
echo $UBUNTU_CODENAME
wget https://www.ubuntulinux.jp/ubuntu-jp-ppa-keyring.gpg -P /etc/apt/trusted.gpg.d/
wget https://www.ubuntulinux.jp/ubuntu-ja-archive-keyring.gpg -P /etc/apt/trusted.gpg.d/
wget https://www.ubuntulinux.jp/sources.list.d/groovy.list -O /etc/apt/sources.list.d/ubuntu-ja.list
elif [ $UBUNTU_VERSION = "20.04" ]; then
echo $UBUNTU_CODENAME
wget -q https://www.ubuntulinux.jp/ubuntu-ja-archive-keyring.gpg -O- | apt-key add -
wget -q https://www.ubuntulinux.jp/ubuntu-jp-ppa-keyring.gpg -O- | apt-key add -
wget https://www.ubuntulinux.jp/sources.list.d/focal.list -O /etc/apt/sources.list.d/ubuntu-ja.list
elif [ $UBUNTU_VERSION = "18.04" ]; then
echo $UBUNTU_CODENAME
wget -q https://www.ubuntulinux.jp/ubuntu-ja-archive-keyring.gpg -O- | apt-key add -
wget -q https://www.ubuntulinux.jp/ubuntu-jp-ppa-keyring.gpg -O- | apt-key add -
wget https://www.ubuntulinux.jp/sources.list.d/bionic.list -O /etc/apt/sources.list.d/ubuntu-ja.list
else
:
fi
apt-get -y update
apt-get -y upgrade
apt-get -y install ubuntu-defaults-ja
# locale
update-locale LANG=ja_JP.UTF8
# manual, if need
apt-get -y install manpages-ja manpages-ja-dev
# timezone
TIMEZONE="Asia/Tokyo"
echo $TIMEZONE > /etc/timezone
cp /usr/share/zoneinfo/${TIMEZONE} /etc/localtime # This sets the time
日本語環境構築の参考:
- http://ubuntulinux.jp/japanese
- https://www.yokoweb.net/2018/05/04/ubuntu-18_04-lts-server-japanese/
- https://askubuntu.com/questions/323131/setting-timezone-from-terminal
- https://askubuntu.com/questions/3375/how-to-change-time-zone-settings-from-the-command-line
- https://serverfault.com/questions/94991/setting-the-timezone-with-an-automated-script