やりたきこと
TableauでDBに繋ぎたいけど、DBがprivate subnetにあるからproxyサーバ経由でアクセスしたい
っていうのをTerraformで書きたい。

資源
| service | OS | subnet | note |
|---|---|---|---|
| RDS | MySQL(Auroraじゃない) | private | |
| EC2 | centos | public | 作業用サーバなのでなんでも |
やること
Terraformで
- EC2立てる(ubuntu t2.micro)
- haproxyインストールする
- 自分用設定ファイルを転送して配置する
- haproxyを再起動する
- Tableau DesktopでRDSにアクセスしてみる
スタート
$ cat main.tf
provider "aws" {
access_key = "${var.access_key}"
secret_key = "${var.secret_key}"
region = "${var.region}"
}
# SGつくるやつ
resource "aws_security_group" "util-server" {
name = "example_sg_util_server"
description = "terraform example"
vpc_id = "${data.aws_vpc.main.id}"
ingress {
from_port = 3306
to_port = 3306
protocol = "tcp"
cidr_blocks = ["許せるIP"]
}
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"]
}
}
#EC2つくるやつ
resource "aws_instance" "example" {
ami = "ami-07ad4b1c3af1ea214"
instance_type = "t2.micro"
key_name = "${var.key_name}"
vpc_security_group_ids = [
"${aws_security_group.util-server.id}",
]
provisioner "remote-exec" {
connection {
type = "ssh"
user = "ubuntu"
private_key = "${file("${var.key_name_full}")}"
}
inline = [
"sudo apt-get update -y && sudo apt-get upgrade -y",
"sudo apt-get install -y haproxy"
]
}
provisioner "file" {
source = "haproxy.cfg"
destination = "/etc/haproxy"
}
tags = {
Name = "${var.ec2_nametag}"
}
}
#EIPつくるやつ(PublicIPでもいいなら、別にEIPは不要かも)
resource "aws_eip" "ip" {
instance = "${aws_instance.example.id}"
}
戦った跡
EC2構築時、apt-get内のgrub更新で3択迫られてるうちにtime outする。

terraformでapt-get update -y したけど、grubの更新でバグったファミコンみたいになる
apt-get-upgrade内のgrub更新の際、対応をn択で迫られるのだけど、GUIライクなCUIで聞かれるため標準出力がひどくなる。
そして、Terraformで答えられないので、time out待ちになってしまう。(9分待ってtime outしなかったけど)
provisioner "remote-exec" {
connection {
type = "ssh"
user = "ubuntu"
private_key = "${file("${var.key_name_full}")}"
}
inline = [
★ "echo grub-pc hold | sudo dpkg --set-selections && sudo apt-get update -y && sudo apt-get upgrade -y",
"sudo apt-get install -y haproxy"
]
}
参考:Vagnrat Ubuntu16.04 apt upgrade のGRUBで更新が止まる時の対策 - Qiita
上手くいったっぽい
aws_instance.example: Still creating... (3m10s elapsed) aws_instance.example: Creation complete after 3m11s (ID: i-0ac91b7d5c7141c5d) aws_eip.ip: Creating... allocation_id: "" => "<computed>" association_id: "" => "<computed>" domain: "" => "<computed>" instance: "" => "i-0ac91b7d5c7141c5d" network_interface: "" => "<computed>" private_ip: "" => "<computed>" public_ip: "" => "<computed>" public_ipv4_pool: "" => "<computed>" vpc: "" => "<computed>"
作成したEC2にログインして確認してみる
$ systemctl list-unit-files|grep haproxy haproxy.service enabled $ ps -ef|grep haproxy root 16460 1 0 04:29 ? 00:00:00 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid haproxy 16461 16460 0 04:29 ? 00:00:00 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid ubuntu 16742 16685 0 04:44 pts/0 00:00:00 grep --color=auto haproxy
haproxyがインストールされてて、起動もされている。
次は自分用のhaproxy設定ファイル置きたい。
file句?とりあえず突っ込んでみる。
provisioner "file" {
source = "haproxy.cfg"
destination = "/etc/haproxy/"
}
ssh: handshake failed: ssh: unable to authenticate
Error: Error applying plan: 1 error(s) occurred: * aws_instance.example: timeout - last error: ssh: handshake failed: ssh: unable to authenticate, attempted methods [none], no supported methods remain
haproxyのインストールは上手くいってる。
ubuntu@ip-172-31-41-172:~$ dpkg -l|grep hapro ii haproxy 1.8.8-1ubuntu0.3 amd64 fast and reliable load balancing reverse proxy ubuntu@ip-172-31-41-172:~$ ps -ef|grep hap root 1993 1 0 07:31 ? 00:00:00 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid haproxy 1994 1993 0 07:31 ? 00:00:00 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /run/haproxy.pid ubuntu 2256 2241 0 07:40 pts/0 00:00:00 grep --color=auto hap
たぶん二つ目のprovisioner句にConnectionを指定してないからかも。
provisioner "remote-exec" {
connection {
type = "ssh"
user = "ubuntu"
private_key = "${file("${var.key_name_full}")}"
}
inline = [
"echo grub-pc hold | sudo dpkg --set-selections",
"sudo apt-get update -y && sudo apt-get upgrade -y",
"sudo apt-get install -y haproxy"
]
}
provisioner "file" {
source = "haproxy.cfg"
destination = "/etc/haproxy/"
}
とりあえず、connectionを入れてみる。
provisioner "remote-exec" {
connection {
type = "ssh"
user = "ubuntu"
private_key = "${file("${var.key_name_full}")}"
}
inline = [
"echo grub-pc hold | sudo dpkg --set-selections",
"sudo apt-get update -y && sudo apt-get upgrade -y",
"sudo apt-get install -y haproxy"
]
}
provisioner "file" {
connection {
type = "ssh"
user = "ubuntu"
private_key = "${file("${var.key_name_full}")}"
}
source = "haproxy.cfg"
destination = "/etc/haproxy/"
}
二重になってダサいけど、直った。
provisioner "file"のpermission denied
上のsshのエラーは直ったけど、今度はpermission denied。
aws_instance.example: Provisioning with 'file'... Error: Error applying plan: 1 error(s) occurred: * aws_instance.example: Upload failed: scp: /etc/haproxy/haproxy: Permission denied
ファイルは置ける場所に置いて、remote-execでsudo権限を使って置きたい場所に置きましょう、らしい。
If your SSH user doesn't have access, what we recommend is using the file provisioner to upload to a place you can, then the remote shell provisioner to
sudo(or similar) to move it.
↓のように修正
- haproxyの設定ファイルを転送しておく
- 脳死でapt-get update && upgrade
- haproxyインストール
- 転送しておいたhaproxy設定ファイルを/etc/haproxy/配下に移動
- systemctlで再起動
provisioner "file" {
connection {
type = "ssh"
user = "ubuntu"
private_key = "${file("${var.key_name_full}")}"
}
source = "haproxy.cfg"
destination = "/tmp/haproxy.cfg"
}
provisioner "remote-exec" {
connection {
type = "ssh"
user = "ubuntu"
private_key = "${file("${var.key_name_full}")}"
}
inline = [
"echo grub-pc hold | sudo dpkg --set-selections",
"sudo apt-get update -y && sudo apt-get upgrade -y",
"sudo apt-get install -y haproxy && sudo mv /tmp/haproxy.cfg /etc/haproxy/. && sudo systemctl restart haproxy.service"
]
}
再起動されてそう。
Feb 5 09:13:59 ip-172-31-47-197 systemd[1]: Stopping HAProxy Load Balancer... Feb 5 09:13:59 ip-172-31-47-197 systemd[1]: haproxy.service: Main process exited, code=exited, status=143/n/a Feb 5 09:13:59 ip-172-31-47-197 systemd[1]: haproxy.service: Failed with result 'exit-code'. Feb 5 09:13:59 ip-172-31-47-197 systemd[1]: Stopped HAProxy Load Balancer. Feb 5 09:13:59 ip-172-31-47-197 systemd[1]: Starting HAProxy Load Balancer... Feb 5 09:13:59 ip-172-31-47-197 systemd[1]: Started HAProxy Load Balancer.
RDSのSGを開ける
RDSのSGにTerraformで作ったEC2のSGを登録してあげる。
Tableauにアクセスしてみる

行けてそう。(繋ぎたい案件対応で入れただけなので使い方は分からない)
DBがWordpressなのは、RDSが別件で検証用に立てたこやつしかいなかったから。。。

出来上がったtf
$ cat main.tf
provider "aws" {
access_key = "${var.access_key}"
secret_key = "${var.secret_key}"
region = "${var.region}"
}
resource "aws_security_group" "util-server" {
name = "example_sg_util_server"
description = "terraform example"
vpc_id = "${data.aws_vpc.main.id}"
ingress {
from_port = 3306
to_port = 3306
protocol = "tcp"
cidr_blocks = ["許せるIP"]
}
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"]
}
}
resource "aws_instance" "example" {
ami = "ami-07ad4b1c3af1ea214"
instance_type = "t2.micro"
key_name = "${var.key_name}"
vpc_security_group_ids = [
"${aws_security_group.util-server.id}",
]
provisioner "file" {
connection {
type = "ssh"
user = "ubuntu"
private_key = "${file("${var.key_name_full}")}"
}
source = "haproxy.cfg"
destination = "/tmp/haproxy.cfg"
}
provisioner "remote-exec" {
connection {
type = "ssh"
user = "ubuntu"
private_key = "${file("${var.key_name_full}")}"
}
inline = [
"echo grub-pc hold | sudo dpkg --set-selections",
"sudo apt-get update -y && sudo apt-get upgrade -y",
"sudo apt-get install -y haproxy && sudo mv /tmp/haproxy.cfg /etc/haproxy/. && sudo systemctl restart haproxy.service"
]
}
tags = {
Name = "${var.ec2_nametag}"
}
}
resource "aws_eip" "ip" {
instance = "${aws_instance.example.id}"
}
$ cat variables.tf
variable "access_key" {
type = "string"
default = "hogehoge"
}
variable "secret_key" {
type = "string"
default = "hogehoge"
}
variable "region" {
default = "ap-northeast-1"
}
variable "key_name" {
type = "string"
default = "mng"
}
variable "key_name_full" {
type = "string"
default = "mng.pem"
}
variable "vpc_id" {
type = "string"
default = "vpc-hoge"
}
variable "ec2_nametag" {
type = "string"
default = "util-server"
}
残ってる課題
RDSに登録したSGを消さないとterraform destroyがスタックする
aws_security_group.util-server: Still destroying... (ID: sg-0deaaa83a62085e75, 7m0s elapsed) aws_security_group.util-server: Still destroying... (ID: sg-0deaaa83a62085e75, 7m10s elapsed) aws_security_group.util-server: Still destroying... (ID: sg-0deaaa83a62085e75, 7m20s elapsed) aws_security_group.util-server: Still destroying... (ID: sg-0deaaa83a62085e75, 7m30s elapsed) aws_security_group.util-server: Still destroying... (ID: sg-0deaaa83a62085e75, 7m40s elapsed) aws_security_group.util-server: Still destroying... (ID: sg-0deaaa83a62085e75, 7m50s elapsed) aws_security_group.util-server: Still destroying... (ID: sg-0deaaa83a62085e75, 8m0s elapsed) aws_security_group.util-server: Still destroying... (ID: sg-0deaaa83a62085e75, 8m10s elapsed)
terraform destroy時にEC2用に作ったSGの削除を行っているが、RDS側のSGで参照しているとEC2用が削除できない。
エラー時にcontinueするみたいな構文あった気がするけど、この場合はずっと待ちなわけで、スキップするようなやつないかな。