AWS EKS에서 EC2 인스턴스 노드그룹으로 사용 가능한 AMI는 크게 세 가지 유형이 존재합니다. 이 중에서 Bottlerocket AMI를 사용해 Managed AMI를 사용하는 것과 어떤 차이가 있는지 살펴보려 합니다.
- Managed AMI : AWS 제공하는 관리형 AMI 입니다.
- Custom AMI : AWS 제공하는 AMI에 Custom한 프로세스 등을 더해 사용하는 AMI 입니다. (사내 보안팀에서 요구하는 별도 서비스 등을 설치 할때 사용하곤 합니다.)
- Bottlerocket AMI : AWS에서 후원하고 지원하는 오픈 소스 Linux 배포판이며, Bottlerocket는 컨테이너 워크로드를 호스팅하기 위해 특별히 제작되었습니다. 컨테이너를 실행하기 위한 전용 AMI 입니다.
AWS 공식 문서에 따르면, Bottlerocket 사용 시 아래와 같은 장점이 있습니다.
- 운영 비용 절감 및 관리 복잡성 감소로 가동 시간 증가 – Bottlerocket은 다른 Linux 배포판보다 리소스 공간이 작고 부팅 시간이 짧으며 보안 위협에 덜 취약합니다. Bottlerocket은 공간이 작아 스토리지, 컴퓨팅 및 네트워킹 리소스를 적게 사용하여 비용을 절감할 수 있습니다.
- 자동 OS 업데이트로 보안 강화 – Bottlerocket 업데이트는 필요한 경우 롤백할 수 있는 단일 단위로 적용됩니다. 이렇게 하면 시스템을 사용 불가 상태로 둘 수 있는 손상되거나 실패한 업데이트의 위험이 제거됩니다. Bottlerocket을 사용하면 보안 업데이트를 사용할 수 있는 즉시 중단을 최소화하는 방식으로 자동 적용하고 장애 발생 시 롤백할 수 있습니다.
- 프리미엄 지원 – AWS에서 제공하는 Amazon EC2 기반 Bottlerocket 빌드에는 Amazon EC2, Amazon EKS, Amazon ECR 등의 AWS 서비스에도 적용되는 동일한 AWS Support 플랜이 적용됩니다.
위와 같은 장점이 있다고 해서 현업에서 바로 사용하기에 고려해야 하는 부분도 당연히 존재합니다.
- Bottlerocket은 x86_64 및 arm64 프로세서가 있는 Amazon EC2 인스턴스를 지원합니다. Bottlerocket AMI를 Inferentia 칩이 있는 Amazon EC2 인스턴스와 함께 사용하는 것은 권장되지 않습니다.
- Bottlerocket 이미지에는 SSH 서버 또는 쉘이 포함되지 않습니다. 대역 외 액세스 방법을 사용하여 SSH를 허용할 수 있습니다.
여기까지 읽어 드는 생각이 Bottlerocket AMI를 사용하고 싶은데, 쉘이 존재하지 않는다면, 사내 보안팀 요구사항을 어떻게 만족시키나 ? 보안팀에서 요구하는 여러가지 서비스가 반드시 AMI에 포함되어야 하는데..? 라고 생각하실 수 있는데, 이런 경우를 위해 Bottlerocket에서는 관리 컨테이너라는 게 존재하고, 관리 컨테이너를 활성화하고 사용자 데이터와 함께 일부 부트스트래핑 구성 단계를 전달할 수 있습니다. (이번 글에서는 해당 내용을 포함하진 않습니다. 이후 주차 과제에서 조금 더 Deep Dive 해보려고 합니다.)
eksctl을 통해 EKS 클러스터를 생성하기 위해 아래와 같이 설정 파일을 작성했습니다.
# NOTE: Bottlerocket AMI might not be available in all regions.
# Please check AWS official doc or below link for more details
# https://github.com/bottlerocket-os/bottlerocket/blob/develop/QUICKSTART.md#finding-an-ami
# A simple example of ClusterConfig object with Bottlerocket settings:
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: bottlerocket-eks
region: ap-northeast-2
nodeGroups:
- name: ng1-public
instanceType: m5.xlarge
desiredCapacity: 2
amiFamily: Bottlerocket
labels:
"network-locality.example.com/public": "true"
bottlerocket:
enableAdminContainer: true
settings:
motd: "Hello, eksctl!"
- name: ng2-public-ssh
instanceType: m5.xlarge
desiredCapacity: 2
amiFamily: Bottlerocket
ssh:
# Enable ssh access (via the admin container)
allow: true
publicKeyName: kp-gasida

1.30 버전을 기본으로 사용하는 것을 알 수 있고, OS-IMAGE를 통해 Bottlerocket OS를 사용하는 노드인 것을 알 수 있습니다.

describe 정보를 확인한 값입니다. (Container Runtime Version을 보면, containerd도 bottlerocket용이 별도로 있는 걸 알 수 있습니다.)

설정을 통해 두 개의 노드 그룹을 생성했습니다. 하나는 Admin 컨테이너가 활성화된 노드그룹이고, 나머자 하나는 SSH가 활성화된 노드그룹입니다.

SSH가 활성화된 노드그룹의 EC2 인스턴스는 SSH가 정상 접속되지만, 비활성화된 EC2 인스턴스는 접속이 안 되는 것을 알 수 있습니다.


SSM을 통해 접속한 EC2 인스턴스입니다.

위 설명과 같이 debug를 위해 "enter-admin-container" 명령어를 통해 쉘을 사용할 수 있습니다.


살펴볼만한 정보들은 아래와 같습니다. apiclient get 명령어로 Bottlerocket API를 통해 시스템 정보를 조회할 수 있습니다. motd 항목을 통해 설정했던 "Hello, eksctl!"을 확인할 수 있습니다.
[root@admin]# apiclient get
{
"os": {
"arch": "x86_64",
"build_id": "cacc4ce9",
"pretty_name": "Bottlerocket OS 1.32.0 (aws-k8s-1.30)",
"variant_id": "aws-k8s-1.30",
"version_id": "1.32.0"
},
"settings": {
"autoscaling": {
"should-wait": false
},
"aws": {
"config": "W2RlZmF1bHRdCnVzZV9maXBzX2VuZHBvaW50PWZhbHNl",
"profile": "default",
"region": "ap-northeast-2"
},
"boot": {
"kernel": {
"initcall_blacklist": [
"vmd_drv_init",
"megasas_init",
"mpt3sas_init",
"pqi_init"
],
"module_blacklist": [
"i8042"
]
}
},
"cloudformation": {
"logical-resource-id": "",
"should-signal": false,
"stack-name": ""
},
"host-containers": {
"admin": {
"enabled": true,
"source": "328549459982.dkr.ecr.ap-northeast-2.amazonaws.com/bottlerocket-admin:v0.11.16",
"superpowered": true,
"user-data": "eyJzc2giOnsiYXV0aG9yaXplZC1rZXlzIjpbXX19"
},
"control": {
"enabled": true,
"source": "328549459982.dkr.ecr.ap-northeast-2.amazonaws.com/bottlerocket-control:v0.7.20",
"superpowered": false
}
},
"kernel": {
"lockdown": "integrity",
"sysctl": {
"vm/nr_hugepages": "0"
}
},
"kubernetes": {
"api-server": "https://92E3C19A65340C7E91D4361B3DA4C856.gr7.ap-northeast-2.eks.amazonaws.com",
"authentication-mode": "aws",
"cloud-provider": "external",
"cluster-certificate": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURCVENDQWUyZ0F3SUJBZ0lJSTdmeWMxMWs0WTB3RFFZSktvWklodmNOQVFFTEJRQXdGVEVUTUJFR0ExVUUKQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TlRBeU1EZ3hOREl4TlRaYUZ3MHpOVEF5TURZeE5ESTJOVFphTUJVeApFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLCkFvSUJBUUQyYTVIVUlBdm9ueHNtb3E2ZmQwVDlvNVFhZ1NMenJWMHdCNFM3RGpPemhJaU9MVEUvbHB2d1RMYzIKVC93T0J4anRoSk1nb1Noa2wwSUFMMWR6cE54NlllNHY5bjJ0QkRqNFdydCtudmZZRTBUY1BUUE5wSEI3V0diaApiT0l4bmlKM0ZsU2NMZGpvZFhWaFRmQVZ2Yk5RSUVqRTY4cGNteFZiUXd4MkFVY0FLWjZXUXpGMVNiUHhOOSt3CjFnYlFYUm4xOW1YZFRMVm1Tdzl0QmxLVllqYmRWSDdLdmpIRWJiL1RmM0VacmZTT0grSEZ1YUd6QkwwYVlYUVYKQkN1Y3NURU93TUJyUE5qZSttc055a1NkeGwzbGFDQ0I0djRZTndnSGhNTDY5a3JIQStuZmRXNUEzSGFBVStDeQpNOTFqeklMMXV3T25NRlJ4cEp1M1ZUVVJWWFQ1QWdNQkFBR2pXVEJYTUE0R0ExVWREd0VCL3dRRUF3SUNwREFQCkJnTlZIUk1CQWY4RUJUQURBUUgvTUIwR0ExVWREZ1FXQkJSTW1pYnZCWktzK1ZSd3AzaUc2U2lMbjJLQ2dqQVYKQmdOVkhSRUVEakFNZ2dwcmRXSmxjbTVsZEdWek1BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQjlGaEtnUFpFUQpZaUtPTVlsMGdEMThONE9RTDJ6T1FXNzQ1ZDBsS1JvUEEwWlRJYzFVVUlDZ3ZLeXhXb1V0L3FQQzZEVU02WWYvCjM1a3lEWXI5STRERWlCbmlNa3R5anNITlBSMzdqb01OaGxtQ1c0K0VEbE9XTW16dnNLVjVPSVFXcU1xUXhRZ2gKR2tncEdITFBHRHpvSE91czhNNnRXaW9iYjZZblFXTldWR3ZhSEpOVFJndHdSZXpWcGtia2hVbVpJMWloUktCZwpmYUpGMHNnS2ZSRVEzWit6VVNSNU5vZm4rV3JSclNXcDBWNll3aEluWXpWSmpZd1Vrdm5VUEdTTzZuRFdKNkNDCmVMMUJVdTJKUWEyajRiSTYwZmZLY0VRSkpibEdtQUY5L1lneUJYZXh5c0Z6UmVGZEJ5TndqaWFkRGZ3RE5ZUTUKNVdaOFJGTDFjcEd6Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K",
"cluster-dns-ip": "10.100.0.10",
"cluster-domain": "cluster.local",
"cluster-name": "bottlerocket-eks",
"credential-providers": {
"ecr-credential-provider": {
"cache-duration": "12h",
"enabled": true,
"image-patterns": [
"*.dkr.ecr.*.amazonaws.com",
"*.dkr.ecr.*.amazonaws.com.cn",
"*.dkr.ecr-fips.*.amazonaws.com",
"*.dkr.ecr.us-iso-east-1.c2s.ic.gov",
"*.dkr.ecr.us-isob-east-1.sc2s.sgov.gov"
]
}
},
"device-ownership-from-security-context": false,
"hostname-override": "ip-192-168-21-133.ap-northeast-2.compute.internal",
"hostname-override-source": "private-dns-name",
"max-pods": 58,
"node-ip": "192.168.21.133",
"node-labels": {
"alpha.eksctl.io/cluster-name": "bottlerocket-eks",
"alpha.eksctl.io/nodegroup-name": "ng1-public",
"network-locality.example.com/public": "true"
},
"provider-id": "aws:///ap-northeast-2c/i-092acf078acfeaf3d",
"seccomp-default": false,
"server-tls-bootstrap": true,
"standalone-mode": false
},
"metrics": {
"metrics-url": "https://metrics.bottlerocket.aws/v1/metrics",
"send-metrics": true,
"service-checks": [
"apiserver",
"chronyd",
"containerd",
"host-containerd",
"kubelet"
]
},
"motd": "Hello, eksctl!",
"network": {
"hostname": "ip-192-168-21-133.ap-northeast-2.compute.internal"
},
"ntp": {
"options": [
"iburst"
],
"time-servers": [
"169.254.169.123",
"2.amazon.pool.ntp.org"
]
},
"oci-defaults": {
"capabilities": {
"audit-write": true,
"chown": true,
"dac-override": true,
"fowner": true,
"fsetid": true,
"kill": true,
"mknod": true,
"net-bind-service": true,
"net-raw": true,
"setfcap": true,
"setgid": true,
"setpcap": true,
"setuid": true,
"sys-chroot": true
},
"resource-limits": {
"max-open-files": {
"hard-limit": 1048576,
"soft-limit": 65536
}
}
},
"oci-hooks": {
"log4j-hotpatch-enabled": false
},
"updates": {
"ignore-waves": false,
"metadata-base-url": "https://updates.bottlerocket.aws/2020-07-07/aws-k8s-1.30/x86_64/",
"seed": 593,
"targets-base-url": "https://updates.bottlerocket.aws/targets/",
"version-lock": "latest"
}
}
}
[root@admin]#
호스트 컨테이너 정보를 확인할 수 있는 명령어 입니다.(위에 모든 정보를 확인한 결과에서도 확인할 수 있는 값입니다.)
[root@admin]# apiclient get settings.host-containers
{
"settings": {
"host-containers": {
"admin": {
"enabled": true,
"source": "328549459982.dkr.ecr.ap-northeast-2.amazonaws.com/bottlerocket-admin:v0.11.16",
"superpowered": true,
"user-data": "eyJzc2giOnsiYXV0aG9yaXplZC1rZXlzIjpbXX19"
},
"control": {
"enabled": true,
"source": "328549459982.dkr.ecr.ap-northeast-2.amazonaws.com/bottlerocket-control:v0.7.20",
"superpowered": false
}
}
}
}
노드 성능 비교를 위해 AL2를 사용하는 노드그룹을 하나 더 추가했습니다.
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: bottlerocket-eks
region: ap-northeast-2
nodeGroups:
- name: ng1-public
instanceType: m5.xlarge
desiredCapacity: 2
amiFamily: Bottlerocket
labels:
"network-locality.example.com/public": "true"
bottlerocket:
enableAdminContainer: true
settings:
motd: "Hello, eksctl!"
- name: ng2-public-ssh
instanceType: m5.xlarge
desiredCapacity: 2
amiFamily: Bottlerocket
ssh:
# Enable ssh access (via the admin container)
allow: true
publicKeyName: kp-gasida
- name: ng3-al2
instanceType: m5.xlarge
desiredCapacity: 2
amiFamily: AmazonLinux2
labels:
"network-locality.example.com/public": "true"
ssh:
allow: true
publicKeyName: kp-gasida

컨테이너 실행 성능 테스트를 비교해볼 수 있는 주요 지표 중 하나인 노드 준비 시간을 비교해보려고 합니다. 먼저, Bottlerocket EC2 인스턴스의 준비 시간은 12초입니다. (12초는 CreationTimestamp에서 KubeletReady 까지 걸린 시간입니다.)

AL2 인스턴스의 준비 시간은 13초입니다. (엄청난 차이가 날 거라고 예상했지만, 실제 결과는 1초 차이입니다.)

Prometheus를 통해 추가 메트릭을 수집해 비교해보고, 컨테이너 시작 시간 측정을 추가로 검토해보려고 합니다. 또한, 주요 차이로 Bottlerocket이 보안 성능이 더 좋다고 하는데, 해당 부분을 어떻게 비교해볼 수 있을지 고민 중입니다..
참고자료
https://github.com/bottlerocket-os/bottlerocket
GitHub - bottlerocket-os/bottlerocket: An operating system designed for hosting containers
An operating system designed for hosting containers - bottlerocket-os/bottlerocket
github.com
https://docs.aws.amazon.com/eks/latest/userguide/eks-optimized-ami-bottlerocket.html
Create nodes with optimized Bottlerocket AMIs - Amazon EKS
Help improve this page Want to contribute to this user guide? Choose the 📝 Edit this page on GitHub link that is located at the bottom of every page. Your contributions will help make our user guide better for everyone. Create nodes with optimized Bottl
docs.aws.amazon.com