hoge-hogeoのひきこもごも

インフラエンジニアだけど形を持ったインフラを触ったことがない人の徒然

Terraform: Tableau用のプロキシサーバを立てたい

やりたきこと

TableauでDBに繋ぎたいけど、DBがprivate subnetにあるからproxyサーバ経由でアクセスしたい

っていうのをTerraformで書きたい。

f:id:hoge-hogeo:20190205183627p:plain

資源

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する。

f:id:hoge-hogeo:20190205185405p:plain

terraformでapt-get update -y したけど、grubの更新でバグったファミコンみたいになる

apt-get-upgrade内のgrub更新の際、対応をn択で迫られるのだけど、GUIライクなCUIで聞かれるため標準出力がひどくなる。

そして、Terraformで答えられないので、time out待ちになってしまう。(9分待ってtime outしなかったけど)

一旦、脳死grubの更新は省く

  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.

Upload failed: scp: /etc/init.d/sample: Permission denied in file provisioning · Issue #8238 · hashicorp/terraform · GitHub

↓のように修正

  • 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にアクセスしてみる

f:id:hoge-hogeo:20190205182107p:plain

行けてそう。(繋ぎたい案件対応で入れただけなので使い方は分からない)

DBがWordpressなのは、RDSが別件で検証用に立てたこやつしかいなかったから。。。 f:id:hoge-hogeo:20190205182346p:plain

出来上がった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するみたいな構文あった気がするけど、この場合はずっと待ちなわけで、スキップするようなやつないかな。