昨天把 EC2 instance 搬進 private subnet,如果要 debug 要怎麼連進去呢?今天介紹兩種連進 EC2 instance、一種直接進 container 的方式~
最傳統(?)的方式是在 public subnet 開一台跳板機。連進跳板機後,從跳板機用 private IP address 連到 private subnet 的 EC2 instance。
我們有一台非 terraform 管理、用來當作 Gitlab runner 以及 MySQL server 的 EC2 instance 放在 public subnet,它就可以當作跳板機使用。
這個做法要注意 EC2 instance 的 security group 要打開從 VPC 網段連 SSH 的 inbound rule,以及要把 ssh 連線用的 key pair 放進跳板機。
用跳板機連線得多開一台機器,AWS 在今年六月推出一個新功能:EC2 Instance Connect Endpoint。這個功能可以讓我們不需要跳板機就能直接連進 private subnet 中的 EC2 instance!神奇吧~
這個功能不是所有 OS 都支援,可以參考文件看哪些 AMI 是有支援的。它是利用 IAM 權限來做 access control,要能夠用這個方式連 EC2 instance 必須要有相關的權限。另外,除非 endpoint 跟要連線的 EC2 在不同 AZ,不然沒有額外費用的!
resource "aws_ec2_instance_connect_endpoint" "public_1a" {
subnet_id = aws_subnet.public_1a.id
security_group_ids = [aws_security_group.allow_ssh_from_my_ip.id]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EC2InstanceConnect",
"Action": "ec2-instance-connect:OpenTunnel",
"Effect": "Allow",
"Resource": "arn:aws:ec2:[REGION]:[ACCOUNT_ID]:instance-connect-endpoint/[EC2_Instance_Connect_Endpoint_ID]",
"Condition": {
"NumericEquals": {
"ec2-instance-connect:remotePort": "22"
},
"IpAddress": {
"ec2-instance-connect:privateIpAddress": [
"172.16.0.0/16"
]
}
}
},
{
"Sid": "Describe",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeInstanceConnectEndpoints"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
所有 Condition 要符合才會能夠成功連上:
ec2-instance-connect:remotePort
指定 EC2 instance 上可以被連線的 port
ec2-instance-connect:privateIpAddress
指定可以被連線的 EC2 instance 的 private IP
要讓要連線的 EC2 instance 擁有可以從自己 IP 連 SSH 的 security group。
$ ssh -i my-key-pair.pem ec2-user@i-0123456789example \
-o ProxyCommand='aws ec2-instance-connect open-tunnel --instance-id i-0123456789example'
要注意 tunnel 的 web socket 的最大 duration,參數是 --max-tunnel-duration
,預設值 3600 秒(最大值也是 3600 秒),超過這個時間 web socket 就會斷掉,所以連帶 ssh 也會斷掉,所以這個方式不適合長時間使用。
ECS Exec 讓我們可以直接以 AWSCLI 進入 ECS task 的 container,不用連進 EC2 instance 再用 docker exec
進入 container。如果 EC2 instance 無法直接從 internet 連 SSH,前面還得再多加一層跳板機,總共要過三層才能到 container,用 ECS Exec 來 debug 會方便很多~
首先依照 官方文件 在自己電腦上安裝 AWSCLI 的 Session Manager plugin,Ubuntu 的安裝命令摘錄如下:
$ curl "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/ubuntu_64bit/session-manager-plugin.deb" -o "session-manager-plugin.deb"
$ sudo dpkg -i session-manager-plugin.deb
增加 SSM 權限到 ECS task 的 task role:
{
"Statement": [
{
"Action": [
"ssmmessages:CreateControlChannel",
"ssmmessages:CreateDataChannel",
"ssmmessages:OpenControlChannel",
"ssmmessages:OpenDataChannel"
],
"Effect": "Allow",
"Resource": "*"
}
],
"Version": "2012-10-17"
}
在用來連 container 的 IAM user 要加上 ecs:ExecuteCommand
跟 ecs:DescribeTasks
permission:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ECSExecuteCommand",
"Effect": "Allow",
"Action": [
"ecs:ExecuteCommand",
"ecs:DescribeTasks"
],
"Resource": "*"
}
]
}
最後修改 aws_ecs_service.service
attribute enable_execute_command
,改成 true
。重新 deploy 一次 service,確認 task 的 td 是有 task role 的。
然後就可以用 awscli 進入 container 啦!
$ aws ecs execute-command --cluster <cluster-name> \
--task <task-id> \
--container <container-name> \
--interactive \
--command "/bin/bash"