호랑이한테물릴래

Terraform으로 Ansible의 AWS EC2 다이나믹 인벤토리 구성하기 본문

DevOps/Opensource

Terraform으로 Ansible의 AWS EC2 다이나믹 인벤토리 구성하기

호랑이한테물릴래 2022. 9. 27. 15:53
반응형

Ansible을 사용하다보면, 빈번히 삭제되고 생성되는 EC2 인벤토리를 정의하는 것이 쉽지않다.

그러나 Ansible Plugin을 활용해서 Dynamic Inventory를 활용하면 구성된 EC2를 자동으로 인벤토리에 할당하기 때문에 아주 간편하다. 기본적으로 Managed node를 관리하는 Controller node에 다음과 같은 기본설정이 필요하다.

Controller node

- AmazonEC2FullAccess 권한
- Managed node와 통신을 위한 키페어(.pem)
- python과 boto설치

Managed node

- 조회 시 사용될 tag를 설정한다.
- ssh Port가 열려있어야한다. (Ansible은 ssh 프로토콜을 통해서 통신)


Dynamic Inventory 생성

# inventory_aws_ec2.yml

plugin: aws_ec2 # aws_ec2 Plugin 설치
regions:
  - ap-northeast-2 # region 설정
keyed_groups: 
  - key: tags.Name # Name을 기반으로 인스턴스를 그룹핑
filters:
  instance-state-name : running # running 중인 EC2만 할당

Inventory로 사용될 yml파일을 생성한다.

https://docs.ansible.com/ansible/latest/collections/amazon/aws/aws_ec2_inventory.html

Controller EC2 

Controller는 기본적인 설정 외에 Provisioner를 이용해서 생성되는 key-pair를 /home/ubuntu/에 저장, python과 ansible을 설치하는 스크립트를 실행한다.

resource "aws_instance" "ansible_controller" {
  ami           = "ami-0e9bfdb247cc8de84"
  instance_type = "t2.micro"
  iam_instance_profile = aws_iam_instance_profile.profile.name
  subnet_id       = aws_subnet.my_subnet.id
  security_groups = [aws_security_group.ansible_sg.id]
  key_name = aws_key_pair.kp.key_name

    connection {
        user = "ubuntu"
        private_key = file("./${aws_key_pair.kp.key_name}.pem")
        host = self.public_ip
        }
        
    provisioner "file" {
    source      = "./src/inventory_aws_ec2.yml"
    destination = "/home/ubuntu/inventory_aws_ec2.yml"
       }

    provisioner "file" {
    source      = "./${aws_key_pair.kp.key_name}.pem"
    destination = "/home/ubuntu/${aws_key_pair.kp.key_name}.pem"
       }
    
    provisioner "file" {
    source      = "./src/ansible.cfg"
    destination = "/etc/ansible/ansible.cfg"
    }


    provisioner "remote-exec" {
        inline = [
            "sudo apt-get update",
            "yes | sudo apt-add-repository ppa:ansible/ansible",
            "yes | sudo add-apt-repository ppa:deadsnakes/ppa",
            "sudo apt-get update",
            "sudo apt-get install ansible -y",
            "sudo apt install python3.8 -y",
            # "sudo apt-get install python3-pip -y",
            # "pip3 install boto3 -y",
            ]
    }

    tags = {
    Name = "controller"
       }
}

특히 Controller는 VPC 내의 모든 EC2에 접근할 수 있는 권한이 필요하다. iam_instance_profile을 이용해서 생성한 role를 적용시킨다.

resource "aws_iam_role" "role" {
  name = "role"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF

  tags = {
      tag-key = "tag-value"
  }
}

resource "aws_iam_instance_profile" "profile" {
  name = "profile"
  role = "${aws_iam_role.role.name}"
}

resource "aws_iam_role_policy" "policy" {
  name = "policy"
  role = "${aws_iam_role.role.id}"

  policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "ec2:*",
            "Effect": "Allow",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "elasticloadbalancing:*",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "cloudwatch:*",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "autoscaling:*",
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "iam:CreateServiceLinkedRole",
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "iam:AWSServiceName": [
                        "autoscaling.amazonaws.com",
                        "ec2scheduled.amazonaws.com",
                        "elasticloadbalancing.amazonaws.com",
                        "spot.amazonaws.com",
                        "spotfleet.amazonaws.com",
                        "transitgateway.amazonaws.com"
                    ]
                }
            }
        }
    ]
}
EOF
}

 

Managed EC2 

managed node는 2개를 생성해서 controller로 제어해보는 테스트를 해보려고 한다. 미리 정의한 managed_node.sh 파일을 user_data로 호출하여 기본적인 python 설치를 진행한다.

resource "aws_instance" "managed_server_1" {
  ami           = "ami-0e9bfdb247cc8de84"
  instance_type = "t2.micro"
  iam_instance_profile = aws_iam_instance_profile.profile.name
  subnet_id       = aws_subnet.my_subnet.id
  security_groups = [aws_security_group.ansible_sg.id]
  key_name = aws_key_pair.kp.key_name
  user_data = "${file("./src/managed_node.sh")}"

    tags = {
    Name = "managed_server_1"
       }
}

resource "aws_instance" "managed_server_2" {
  ami           = "ami-0e9bfdb247cc8de84"
  instance_type = "t2.micro"
  iam_instance_profile = aws_iam_instance_profile.profile.name
  subnet_id       = aws_subnet.my_subnet.id
  security_groups = [aws_security_group.ansible_sg.id]
  key_name = aws_key_pair.kp.key_name
  user_data = "${file("./src/managed_node.sh")}"

    tags = {
    Name = "managed_server_2"
       }
}

 

Key-pair

Controller node는 다른 managed node에 접근하기 위해서 key-pair가 필요하다. 아래와 같이 생성해서 local에 다운로드한 후, 위 provisoner를 통해서 controller node에 업로드한다.

# RSA 알고리즘을 이용해 private 키 생성
resource "tls_private_key" "pk" {
  algorithm = "RSA"
  rsa_bits  = 4096
}

# private 키를 가지고 keypair 파일 생성
resource "aws_key_pair" "kp" {
  key_name   = "ansible_key"
  public_key = tls_private_key.pk.public_key_openssh
}

# 키 파일을 생성하고 로컬에 다운로드
resource "local_file" "ssh_key" {
  filename = "${aws_key_pair.kp.key_name}.pem"
  content = tls_private_key.pk.private_key_pem
}

작동 테스트에 앞서, ansible의 Configuration 파일인 /etc/ansible/ansible.cfg을 다음과 같이 수정한다.

# ansible.cfg

[defaults]
remote_user = ubuntu # managed server의 user
host_key_checking = False
inventory=/home/ubuntu/inventory_aws_ec2.yml # 기본 Inventory 파일 지정
interpreter_python=auto_silent
private_key_file= /home/ubuntu/ansible_key.pem # 적용할 key-pair

준비되었다면 정상적으로 작동하는지 확인하기 위해 명령어를 실행해본다.

$ ansible-inventory -i inventory_aws_ec2.yml --graph

위와같이 VPC내에 EC2 리스트를 확인할 수 있다.

간단한 ping test를 할 수 있는 ping-playbook.yml을 만든다.

# ping-playbook.yml

- name: ping them all
  hosts: all
  tasks:
    - name: pinging
      ping:

ansible-playbook으로 실행하면 아래와같이 ping 테스트가 성공적으로 뜬다.

 

반응형
0 Comments
댓글쓰기 폼