스터디/AEWS

[AEWS] 7주차 AWS Fargate

안녕유지 2025. 3. 29. 19:42
Cloudnet AEWS 7주차 스터디를 진행하며 정리한 글입니다.

 

이번 포스팅은 AWS Fargate에 대해 알아보도록 하겠습니다.

 

Fargate

컨테이너를 서버 없이(serverless) 실행할 수 있게 해주는 컨테이너 실행 엔진입니다.

EC2 노드 없이 파드를 띄울 수 있는 서버리스 실행환경을 제공합니다.

https://www.eksworkshop.com/docs/fundamentals/fargate/

 

 

EKS Fargate 아키텍처 (추정)

CloudNet 제공 - 가시다님

 

사용자가 Fargate Profile을 정의하면, 해당 프로파일에 지정된 네임스페이스 또는 파드 라벨에 해당하는 파드는 자동으로 Fargate에서 실행됩니다. 이때 EKS Control Plane 내부의 Webhook과 Fargate Scheduler가 동작하여, 적절한 실행 환경을 확보하고, Pod를 실행할 수 있는 MicroVM을 생성하게 됩니다.

Fargate는 이 MicroVM을 사용자 대신 자동으로 구성하고, 네트워크적으로도 사용자 VPC와 Fargate 전용 VPC를 분리하여 관리하지만, Pod에는 ENI가 직접 할당되어 사용자 VPC 안에서 실행되는 것처럼 동작한다는 점을 알 수 있습니다.

 

CloudNet 제공 - 가시다님

 

일반적인 EKS에서는 하나의 EC2 노드 위에 여러 개의 Pod가 올라가고, 해당 노드에 kubelet, containerd, kube-proxy와 같은 Kubernetes 구성 요소가 설치되어 있어야 합니다. 하지만 Fargate는 EC2를 사용하지 않고도 Pod를 실행합니다. 이때, Pod 1개를 실행하기 위해 필요한 최소한의 노드 환경을 AWS가 자동으로 구성해주는데, 이 환경이 바로 MicroVM입니다.

MicroVM은 1회용 가상 머신처럼 동작하며, 각 MicroVM에는 Pod 1개만 올라가고, 내부에 kubelet, containerd, kube-proxy가 함께 실행됩니다. 이런 방식은 각 Pod를 VM 수준으로 완전히 격리할 수 있어 보안성이 매우 높고, 이 구조는 사용자에게는 보이지 않습니다. 

 

Firecracker

Fargate는 Firecracker라는 초경량 가상머신 하이퍼바이저를 사용하여 MicroVM을 실행합니다. Firecracker는 AWS가 EC2, Fargate, Lambda 등에 최적화된 경량 가상화 환경을 만들기 위해 직접 개발한 기술입니다.

Firecracker는 기존 VM처럼 격리 수준이 높으면서도, Docker처럼 빠르고 가볍게 실행할 수 있도록 만들어졌습니다.

이런 특징 덕분에 Fargate는 Pod 단위로 독립된 실행 환경을 제공하면서도 EC2보다 빠르고 가볍게 컨테이너를 띄울 수 있습니다.

 

https://github.com/firecracker-microvm/firecracker

 

GitHub - firecracker-microvm/firecracker: Secure and fast microVMs for serverless computing.

Secure and fast microVMs for serverless computing. - firecracker-microvm/firecracker

github.com

 

 

Fargate 배포 실습

❯ kubectl cluster-info
Kubernetes control plane is running at https://1A421EA489DB371F1506DC5ECDE0872B.gr7.ap-northeast-2.eks.amazonaws.com
CoreDNS is running at https://1A421EA489DB371F1506DC5ECDE0872B.gr7.ap-northeast-2.eks.amazonaws.com/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

❯ kubectl get node
NAME                                                      STATUS   ROLES    AGE   VERSION
fargate-ip-10-10-18-197.ap-northeast-2.compute.internal   Ready    <none>   9d    v1.30.8-eks-2d5f260
fargate-ip-10-10-2-136.ap-northeast-2.compute.internal    Ready    <none>   9d    v1.30.8-eks-2d5f260
fargate-ip-10-10-39-145.ap-northeast-2.compute.internal   Ready    <none>   9d    v1.30.8-eks-2d5f260
fargate-ip-10-10-42-75.ap-northeast-2.compute.internal    Ready    <none>   9d    v1.30.8-eks-2d5f260

❯ kubectl get pod -A
NAMESPACE     NAME                                            READY   STATUS    RESTARTS   AGE
kube-system   aws-load-balancer-controller-7cd5fb85c4-2x667   1/1     Running   0          9d
kube-system   aws-load-balancer-controller-7cd5fb85c4-rx6bp   1/1     Running   0          9d
kube-system   coredns-64696d8b7f-2hjmt                        1/1     Running   0          9d
kube-system   coredns-64696d8b7f-6dg6l                        1/1     Running   0          9d

 

클러스터는 존재하고, 내부에 파드도 떠있지만 실제 배포된 EC2 서버는 없는 것을 알 수 있습니다.

 

실제로, kube-ops-view 파드를 배포 하였을 때 kube-ops-view가 10.10.31.190이라는 IP로 할당 되어 뜨고, 동일한 IP의 노드개 생성 된 것을 알 수 있습니다. 이는 1개의 Pod는 1개의 MicroVM 구조이기 때문에 파드의 IP와 노드의 IP가 같습니다.

❯ kubectl get pod -n kube-system -o wide
NAME                                            READY   STATUS    RESTARTS   AGE     IP             NODE                                                      NOMINATED NODE   READINESS GATES
aws-load-balancer-controller-7cd5fb85c4-2x667   1/1     Running   0          9d      10.10.39.145   fargate-ip-10-10-39-145.ap-northeast-2.compute.internal   <none>           <none>
aws-load-balancer-controller-7cd5fb85c4-rx6bp   1/1     Running   0          9d      10.10.42.75    fargate-ip-10-10-42-75.ap-northeast-2.compute.internal    <none>           <none>
coredns-64696d8b7f-2hjmt                        1/1     Running   0          9d      10.10.18.197   fargate-ip-10-10-18-197.ap-northeast-2.compute.internal   <none>           <none>
coredns-64696d8b7f-6dg6l                        1/1     Running   0          9d      10.10.2.136    fargate-ip-10-10-2-136.ap-northeast-2.compute.internal    <none>           <none>
kube-ops-view-796947d6dc-jsw7n                  1/1     Running   0          9m20s   10.10.31.190   fargate-ip-10-10-31-190.ap-northeast-2.compute.internal   <none>           <none>   ## 배포

❯ kubectl get node
NAME                                                      STATUS   ROLES    AGE     VERSION
fargate-ip-10-10-18-197.ap-northeast-2.compute.internal   Ready    <none>   9d      v1.30.8-eks-2d5f260
fargate-ip-10-10-2-136.ap-northeast-2.compute.internal    Ready    <none>   9d      v1.30.8-eks-2d5f260
fargate-ip-10-10-31-190.ap-northeast-2.compute.internal   Ready    <none>   9m37s   v1.30.8-eks-2d5f260  ## 배포
fargate-ip-10-10-39-145.ap-northeast-2.compute.internal   Ready    <none>   9d      v1.30.8-eks-2d5f260
fargate-ip-10-10-42-75.ap-northeast-2.compute.internal    Ready    <none>   9d      v1.30.8-eks-2d5f260

 

이 때 ENI를 확인해보면, ENI에 대한 소유자, 요청자, 인스턴스 소유자의 ID가 모두 다른 것을 알 수 있습니다.

  • 소유자 : 본인
  • 요청자 : EKS Fargate 서비스
  • 인스턴스 소유자 ID : AWS 내부 Fargate 계정

 

kube-ops-view의 파드 정보를 확인하겠습니다. default-scheduler가 deployment의 스케줄에 관여하였지만 실제 pod 생성에는 fargate-scheduler가 관여한 것을 알 수 있습니다.

# Deployment 상세 정보
❯ kubectl get deploy -n kube-system kube-ops-view -o yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
    meta.helm.sh/release-name: kube-ops-view
    meta.helm.sh/release-namespace: kube-system
  creationTimestamp: "2025-03-29T10:02:56Z"
  generation: 1
  labels:
    app.kubernetes.io/instance: kube-ops-view
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: kube-ops-view
    app.kubernetes.io/version: 20.4.0
    helm.sh/chart: kube-ops-view-1.2.2
  name: kube-ops-view
  namespace: kube-system
  resourceVersion: "3776198"
  uid: f8ffe497-2103-474d-9f40-af89f3cd8347
spec:
		...
        ports:
        - containerPort: 8080
          name: http
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          periodSeconds: 10
          successThreshold: 1
          tcpSocket:
            port: 8080
          timeoutSeconds: 1
      schedulerName: default-scheduler    ### 확인
      securityContext: {}
      serviceAccount: kube-ops-view
      serviceAccountName: kube-ops-view
      terminationGracePeriodSeconds: 30

  
# Pod 상세 정보
❯ kubectl get pod -n kube-system -l app.kubernetes.io/instance=kube-ops-view -o yaml
apiVersion: v1
items:
- apiVersion: v1
  kind: Pod
  metadata:
    annotations:
      CapacityProvisioned: 0.25vCPU 0.5GB
      Logging: LoggingEnabled
    creationTimestamp: "2025-03-29T10:02:56Z"
    generateName: kube-ops-view-796947d6dc-
    labels:
      app.kubernetes.io/instance: kube-ops-view
      app.kubernetes.io/name: kube-ops-view
      eks.amazonaws.com/fargate-profile: kube-system
      pod-template-hash: 796947d6dc
    name: kube-ops-view-796947d6dc-jsw7n
    namespace: kube-system
    ownerReferences:
    - apiVersion: apps/v1
      blockOwnerDeletion: true
      controller: true
      kind: ReplicaSet
      name: kube-ops-view-796947d6dc
      uid: ebdf2452-ec1b-4515-9c61-155951a97d0f
    resourceVersion: "3776194"
    uid: 40d91efa-f893-4f1b-b70b-93c5af13f5dc
  spec:
    automountServiceAccountToken: true
    containers:
    - env:
      - name: TZ
        value: Asia/Seoul
      image: hjacobs/kube-ops-view:20.4.0
      imagePullPolicy: IfNotPresent
      name: kube-ops-view
      ports:
      - containerPort: 8080
        name: http
        protocol: TCP
		...
    schedulerName: fargate-scheduler  ### 확인
    securityContext: {}
    serviceAccount: kube-ops-view
    serviceAccountName: kube-ops-view
    terminationGracePeriodSeconds: 30
    tolerations:
    - effect: NoExecute
      key: node.kubernetes.io/not-ready
      operator: Exists
      tolerationSeconds: 300
    - effect: NoExecute
      key: node.kubernetes.io/unreachable
      operator: Exists
      tolerationSeconds: 300
    volumes:
    - name: kube-api-access-t2sfm
      projected:
        defaultMode: 420
        sources:
        - serviceAccountToken:
            expirationSeconds: 3607
            path: token
        - configMap:
            items:
            - key: ca.crt
              path: ca.crt
            name: kube-root-ca.crt
        - downwardAPI:
            items:
            - fieldRef:
                apiVersion: v1
                fieldPath: metadata.namespace
              path: namespace

 

 

netshoot 파드 배포하여 Fargate에서의 리소스 요청 및 프로비저닝 확인해보겠습니다.

CPU/Memory 요청과 상관없이 Fargate는 0.5vCPU, 1GB 단위로 고정 리소스를 프로비저닝합니다.

실제로 Pod에 requests: 500m / 500Mi를 줘도, CapacityProvisioned: 0.5vCPU 1GB라는 어노테이션이 붙는 것을 확인할 수 있습니다.

# 네임스페이스 생성
❯ kubectl create ns study-aews

# 테스트용 파드 netshoot 디플로이먼트 생성 : 0.5vCPU 1GB 할당되어, 아래 Limit 값은 의미가 없음. 배포 시 대략 시간 측정해보자!
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: netshoot
  namespace: study-aews
spec:
  replicas: 1
  selector:
    matchLabels:
      app: netshoot
  template:
    metadata:
      labels:
        app: netshoot
    spec:
      containers:
      - name: netshoot
        image: nicolaka/netshoot
        command: ["tail"]
        args: ["-f", "/dev/null"]
        resources: 
          requests:
            cpu: 500m
            memory: 500Mi
          limits:
            cpu: 2
            memory: 2Gi
      terminationGracePeriodSeconds: 0
EOF

# 이벤트 확인
❯ kubectl get events -w --sort-by '.lastTimestamp'
0s          Normal    Starting                  node/fargate-ip-10-10-18-147.ap-northeast-2.compute.internal   Starting kubelet.
0s          Warning   InvalidDiskCapacity       node/fargate-ip-10-10-18-147.ap-northeast-2.compute.internal   invalid capacity 0 on image filesystem
0s          Normal    NodeHasSufficientMemory   node/fargate-ip-10-10-18-147.ap-northeast-2.compute.internal   Node fargate-ip-10-10-18-147.ap-northeast-2.compute.internal status is now: NodeHasSufficientMemory
0s          Normal    NodeHasNoDiskPressure     node/fargate-ip-10-10-18-147.ap-northeast-2.compute.internal   Node fargate-ip-10-10-18-147.ap-northeast-2.compute.internal status is now: NodeHasNoDiskPressure
0s          Normal    NodeHasSufficientPID      node/fargate-ip-10-10-18-147.ap-northeast-2.compute.internal   Node fargate-ip-10-10-18-147.ap-northeast-2.compute.internal status is now: NodeHasSufficientPID
0s          Normal    NodeAllocatableEnforced   node/fargate-ip-10-10-18-147.ap-northeast-2.compute.internal   Updated Node Allocatable limit across pods
0s          Normal    NodeHasSufficientMemory   node/fargate-ip-10-10-18-147.ap-northeast-2.compute.internal   Node fargate-ip-10-10-18-147.ap-northeast-2.compute.internal status is now: NodeHasSufficientMemory
0s          Normal    NodeHasNoDiskPressure     node/fargate-ip-10-10-18-147.ap-northeast-2.compute.internal   Node fargate-ip-10-10-18-147.ap-northeast-2.compute.internal status is now: NodeHasNoDiskPressure
0s          Normal    NodeHasSufficientPID      node/fargate-ip-10-10-18-147.ap-northeast-2.compute.internal   Node fargate-ip-10-10-18-147.ap-northeast-2.compute.internal status is now: NodeHasSufficientPID
0s          Normal    Synced                    node/fargate-ip-10-10-18-147.ap-northeast-2.compute.internal   Node synced successfully
0s          Normal    NodeReady                 node/fargate-ip-10-10-18-147.ap-northeast-2.compute.internal   Node fargate-ip-10-10-18-147.ap-northeast-2.compute.internal status is now: NodeReady
0s          Normal    Starting                  node/fargate-ip-10-10-18-147.ap-northeast-2.compute.internal

# 설정한 값과 달리 리소스가 설정되어있음
 ❯ kubectl get pod -n study-aews -o jsonpath='{.items[0].metadata.annotations.CapacityProvisioned}'
0.5vCPU 1GB%
0s          Normal    RegisteredNode            node/fargate-ip-10-10-18-147.ap-northeast-2.compute.internal   Node fargate-ip-10-10-18-147.ap-northeast-2.compute.internal event: Registered Node fargate-ip-10-10-18-147.ap-northeast-2.compute.internal in Controller

 

또한, 파드 생성 시 이벤트를 보면 스케줄러가 fargate-scheduler인 것을 확인할 수 있는데, 기본 스케줄러가 아닌 Fargate 전용 스케줄러가 동작하고 있음을 확인할 수 있습니다.

따라서 Admission Webhook이 동작해서 파드의 리소스 어노테이션, Priority 설정 등을 자동으로 수정한 것을 알 수 있습니다.

❯ kubectl describe pod -n study-aews -l app=netshoot | grep Events: -A10
Events:
  Type    Reason          Age    From               Message
  ----    ------          ----   ----               -------
  Normal  LoggingEnabled  2m51s  fargate-scheduler  Successfully enabled logging for pod
  Normal  Scheduled       2m9s   fargate-scheduler  Successfully assigned study-aews/netshoot-84558cd8d9-6hfrb to fargate-ip-10-10-18-147.ap-northeast-2.compute.internal
  Normal  Pulling         2m8s   kubelet            Pulling image "nicolaka/netshoot"
  Normal  Pulled          112s   kubelet            Successfully pulled image "nicolaka/netshoot" in 15.649s (15.649s including waiting). Image size: 183950747 bytes.
  Normal  Created         112s   kubelet            Created container netshoot
  Normal  Started         112s   kubelet            Started container netshoot

 

 

netshoot 파드 안에서 명령어를 통해 어떤 인프라 구성을 가지는지 확인해보겠습니다.

 

# netshoot 파드 안에서 확인

# Fargate에서는 파드가 EC2와 동일하게 VPC 내에서 동작하며, kube-proxy나 iptables 기반 NAT를 거치지 않고 직접 네트워크 통신을 함
# Pod는 사용자 VPC에서 직접 통신하는 구조, Fargate가 Pod당 ENI(Elastic Network Interface)를 부여하고, Pod가 VPC 안에서 1급 네트워크 구성원으로 동작
ip -c a

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
4: eth0@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc noqueue state UP group default qlen 1000
    link/ether 2e:73:3a:ce:bf:74 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.10.18.147/20 brd 10.10.31.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::2c73:3aff:fece:bf74/64 scope link
       valid_lft forever preferred_lft forever


# Fargate 환경에서도 클러스터 내 DNS 및 서비스 디스커버리 동작 방식은 동일
cat /etc/resolv.conf
search study-aews.svc.cluster.local svc.cluster.local cluster.local ap-northeast-2.compute.internal
nameserver 172.20.0.10
options ndots:5

# 외부로 나갈 때는 NAT Gateway 또는 IGW를 통해 Public IP로 SNAT됨
curl ipinfo.io/ip
43.202.150.225#

# 클러스터 내부 Pod 간 통신도 정상
# Fargate 파드 간에는 VPC 내에서 직접 통신 가능
ping -c 1 10.10.31.190
PING 10.10.31.190 (10.10.31.190) 56(84) bytes of data.
64 bytes from 10.10.31.190: icmp_seq=1 ttl=125 time=0.905 ms

--- 10.10.31.190 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.905/0.905/0.905/0.000 ms


# Fargate 파드는 컨테이너 이미지 계층 위에 Overlay 파일시스템이 생성됨
# Fargate는 Persistent Volume이나 HostPath를 지원하지 않음, 자체적으로 읽기/쓰기 가능한 Overlay FS만 사용 가능
lsblk
NAME          MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
nvme0n1       259:0    0   5G  0 disk
├─nvme0n1p1   259:2    0   5G  0 part
└─nvme0n1p128 259:3    0   1M  0 part
nvme1n1       259:1    0  30G  0 disk /etc/resolv.conf
                                      /etc/hostname
                                      
df -hT /
Filesystem           Type            Size      Used Available Use% Mounted on
overlay              overlay        29.4G     11.8G     16.0G  43% /

# fstab은 표준 Linux 이미지에 들어있는 기본 템플릿이 실제로는 이 디스크들이 없음 → Fargate에선 의미 없음
cat /etc/fstab
/dev/cdrom	/media/cdrom	iso9660	noauto,ro 0 0
/dev/usbdisk	/media/usb	vfat	noauto,ro 0 0

 

 

Fargate가 보안이 좋다고 하였는데, 이를 확인하기 위한 실습입니다.

파드 생성 시 호스트 네트워크의 네임스페이스를 사용하고, 호스트의 프로세스/IPC 네임스페이스를 공유하고, 컨테이너에 루트 권한을 부여하고, 노드의 루트 디렉터리를 직접 마운트 하는 옵션을 주어 생성하였습니다. 

 

하지만, 파드는 생성되지 않았는데, 에러 메세지를 확인하면 Admission Webhook과 Fargate Scheduler가 Pod 정의를 검토한 후,
Fargate에서 실행할 수 없는 필드가 있으므로 스케줄링을 거부한 것을 알 수 있습니다.

호스트 네임스페이스나 privileged 컨테이너가 필요한 경우에는 Fargate가 아닌 EC2 노드를 선택해야 하겠군요.

❯ kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: root-shell
  namespace: study-aews
spec:
  containers:
  - command:
    - /bin/cat
    image: alpine:3
    name: root-shell
    securityContext:
      privileged: true    # 컨테이너에 루트 권한 부여
    tty: true
    stdin: true
    volumeMounts:
    - mountPath: /host
      name: hostroot
  hostNetwork: true       # Host 네트워크 사용
  hostPID: true
  hostIPC: true
  tolerations:
  - effect: NoSchedule
    operator: Exists
  - effect: NoExecute
    operator: Exists
  volumes:
  - hostPath:            # Host 볼륨 그대로 마운트
      path: /
    name: hostroot
EOF

❯ kubectl get pod -n study-aews root-shell
NAME         READY   STATUS    RESTARTS   AGE
root-shell   0/1     Pending   0          47s

❯ kubectl describe pod -n study-aews root-shell | grep Events: -A 10
Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----               -------
  Warning  FailedScheduling  58s   fargate-scheduler  Pod not supported on Fargate: fields not supported: HostNetwork, HostPID, HostIPC, volumes not supported: hostroot is of an unsupported volume Type, invalid SecurityContext fields: Privileged

 

 

다음은 Fargate에서 Job이 어떻게 실행되는지, 그리고 Job이 완료된 후 리소스가 어떻게 정리 되는지 확인해보겠습니다.

Fargate에서 Job은 잘 실행되지만 ttlSecondsAfterFinished라는 옵션을 주어 TTL Controller를 통해 Job이 끝나고 60초가 지나면 리소스가 삭제됩니다.

cat <<EOF | kubectl apply -f -
apiVersion: batch/v1
kind: Job
metadata:
  name: busybox1
  namespace: study-aews
spec:
  template:
    spec:
      containers:
      - name: busybox
        image: busybox
        command: ["/bin/sh", "-c", "sleep 10"]
      restartPolicy: Never
  ttlSecondsAfterFinished: 60 # <-- TTL controller
---
apiVersion: batch/v1
kind: Job
metadata:
  name: busybox2
  namespace: study-aews
spec:
  template:
    spec:
      containers:
      - name: busybox
        image: busybox
        command: ["/bin/sh", "-c", "sleep 10"]
      restartPolicy: Never
EOF

❯ kubectl get job,pod -n study-aews

NAME                 STATUS    COMPLETIONS   DURATION   AGE
job.batch/busybox1   Running   0/1           10s        10s
job.batch/busybox2   Running   0/1           10s        10s

NAME                            READY   STATUS    RESTARTS   AGE
pod/busybox1-sqb9w              0/1     Pending   0          10s
pod/busybox2-2z67r              0/1     Pending   0          10s

❯ kubectl get job,pod -n study-aews
NAME                 STATUS     COMPLETIONS   DURATION   AGE
job.batch/busybox1   Complete   1/1           61s        80s
job.batch/busybox2   Complete   1/1           68s        80s

NAME                            READY   STATUS      RESTARTS   AGE
pod/busybox1-sqb9w              0/1     Completed   0          80s
pod/busybox2-2z67r              0/1     Completed   0          80s

 

 

Fargate에서는 aws-observability라는 네임스페이스를 통해 로그 수집 구성을 확인할 수 있습니다.

해당 configmap 내용에는 로그 포맷 파싱, 목적지, 등등 옵션 값이 있습니다.

❯ kubectl get cm -n aws-observability          
NAME               DATA   AGE
aws-logging        4      9d
kube-root-ca.crt   1      9d

❯ kubectl get cm -n aws-observability aws-logging -o yaml
apiVersion: v1
data:
  filters.conf: |
    [FILTER]
      Name parser
      Match *
      Key_name log
      Parser crio
    [FILTER]
      Name kubernetes
      Match kube.*
      Merge_Log On
      Keep_Log Off
      Buffer_Size 0
      Kube_Meta_Cache_TTL 300s
  flb_log_cw: "true"
  output.conf: |+
    [OUTPUT]
          Name cloudwatch
          Match kube.*
          region ap-northeast-2
          log_group_name /fargate-serverless/fargate-fluentbit-logs2025031912350445510000000d
          log_stream_prefix fargate-logs-
          auto_create_group true
    [OUTPUT]
          Name cloudwatch_logs
          Match *
          region ap-northeast-2
          log_group_name /fargate-serverless/fargate-fluentbit-logs2025031912350445510000000d
          log_stream_prefix fargate-logs-fluent-bit-
          auto_create_group true

  parsers.conf: |
    [PARSER]
      Name crio
      Format Regex
      Regex ^(?<time>[^ ]+) (?<stream>stdout|stderr) (?<logtag>P|F) (?<log>.*)$
      Time_Key    time
      Time_Format %Y-%m-%dT%H:%M:%S.%L%z
      Time_Keep On
immutable: false
kind: ConfigMap
metadata:
  creationTimestamp: "2025-03-19T12:35:06Z"
  name: aws-logging
  namespace: aws-observability
  resourceVersion: "871"
  uid: ff26c3ab-da4b-4651-99eb-37e62cd2d89d

 

실제로, 로그를 생성하는 파드를 배포하겠습니다. 

Fargate에 2개의 nginx 파드를 배포하여 로그를 발생하여 확인해보겠습니다. 

cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sample-app
  namespace: study-aews
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:latest
        name: nginx
        ports:
        - containerPort: 80
          name: http
        resources:
          requests:
            cpu: 500m
            memory: 500Mi
          limits:
            cpu: 2
            memory: 2Gi
---
apiVersion: v1
kind: Service
metadata:
  name: sample-app
  namespace: study-aews
spec:
  selector:
    app: nginx
  ports:
  - port: 80
    targetPort: 80
    protocol: TCP
  type: ClusterIP
EOF


❯ kubectl get pod -n study-aews -l app=nginx        

NAME                          READY   STATUS    RESTARTS   AGE
sample-app-7596c66778-fpq26   1/1     Running   0          66s
sample-app-7596c66778-v5skx   1/1     Running   0          66s


❯ kubectl exec -it deploy/netshoot -n study-aews -- curl sample-app | grep title
while true; do kubectl exec -it deploy/netshoot -n study-aews -- curl sample-app | grep title; sleep 1; echo ; date; done;
<title>Welcome to nginx!</title>
<title>Welcome to nginx!</title>

Sat Mar 29 19:52:53 KST 2025
<title>Welcome to nginx!</title>

Sat Mar 29 19:52:55 KST 2025
<title>Welcome to nginx!</title>

...

 

수집된 파드 로그는 Cloud Watch Log Stream에서 확인할 수 있습니다.

 

 

 

Fargate 필요한 경우

  • 노드나 인프라 관리 없이 파드만 빠르게 실행하고 싶을 때
    • EC2, 노드 그룹, Karpenter 아무것도 모르고도 Pod 실행 가능
  • 클러스터 보안을 신경 쓰고 싶을 때
    • Pod마다 완전히 분리된 MicroVM에서 실행됨 → 강한 격리
  • 클러스터 규모가 작거나, 사용량이 들쭉날쭉할 때
    • 필요한 파드 수만큼만 과금되어 EC2처럼 고정된 인프라를 유지하지 않아도 되서 비용 낭비 없음

 

 

Fargate 제약 사항

  • 데몬셋은 Fargate에서 지원 불가
  • 특권 컨테이너(Privileged containers)가 지원되지 않음
  • HostPort 또는 HostNetwork를 지정할 수 없음
  • Fargate에서는 GPU를 사용할 수 없음
  • private 서브넷에서만 지원
  • 대체 CNI 플러그인을 사용할 수 없음
  • EFS 동적 영구 볼륨 프로비저닝을 사용할 수 없음
  • Fargate Spot을 지원하지 않음
  • EBS 볼륨을 Fargate 포드에 마운트할 수 없음