Kubernetes – AWS EC2 단일 노드에 ArgoCD + nginx 구성하기 (GitOps, Private 저장소)

By | 2026년 9월 26일
Table of Contents

Kubernetes – AWS EC2 단일 노드에 ArgoCD + nginx 구성하기 (GitOps, Private 저장소)

AWS EC2 인스턴스 한 대에 kubeadm 으로 쿠버네티스를 설치하고, ArgoCD 와 nginx 만 올리는 최소 구성입니다.
모든 설정은 GitHub Private 저장소에 두고, 배포는 ArgoCD 가 Git 을 보고 수행합니다.

EC2 는 메모리가 4GB 이상이어야 하고, 우분투 OS 여야 합니다.

수동으로 하는 작업은 다음 두 가지뿐입니다.

  1. helm install 로 ArgoCD 최초 설치
  2. kubectl apply 로 루트 Application 적용

그 이후로는 Git push 만으로 배포합니다.


0. 전체 구조

GitHub (Private)                                  EC2 (단일 노드 Kubernetes)
k8s-gitops-aws/                                 ┌───────────────────────────┐
├── bootstrap/root-app.yaml  ── (one time) ──▶ │ ArgoCD                    │
├── apps/                                       │  ├─ argocd (Self-managed) │
│   ├── argocd.yaml          ◀── monitor ───   │  └─ nginx                 │
│   └── nginx.yaml                              └───────────────────────────┘
├── values/                    # ★ 환경 설정은 전부 여기
│   ├── argocd/values.yaml
│   └── nginx/values.yaml
└── charts/nginx/              # 자체 앱 차트 (공개 차트가 없는 것만)
    ├── Chart.yaml
    ├── values.yaml
    └── templates/
        ├── deployment.yaml
        └── service.yaml
  • apps/*.yaml : 무엇을, 어느 버전으로 설치할지
  • values/*/values.yaml : 어떻게 설치할지
  • 차트는 Helm 저장소(ArgoCD) 또는 charts/(nginx)에서 가져오고, 설정은 항상 values/ 에서 가져옵니다.
서비스 접속 주소
ArgoCD https://<EC2_PUBLIC_IP>:30443/
nginx http://<EC2_PUBLIC_IP>:31405/

1. EC2 인스턴스 준비

항목 값
AMI Ubuntu 26.04 (x86_64)
인스턴스 타입 t3.medium 이상 (vCPU 2, 메모리 4GB)
스토리지 20GB 이상 (gp3)
기본 사용자 admin

보안 그룹 인바운드 규칙

포트 용도 소스
22 SSH 내 IP
30443 ArgoCD UI 내 IP
31405 nginx 0.0.0.0/0 (필요 시)

6443(API 서버)은 외부에 열 필요가 없습니다. kubectl 은 EC2 안에서 실행합니다.


2. Kubernetes 설치

EC2 에 SSH 로 접속해서 진행합니다.

2.1 기본 패키지 / 스왑 비활성화

sudo apt update && sudo apt upgrade -y
sudo apt install -y curl gnupg ca-certificates apt-transport-https git

# EC2 는 기본적으로 스왑이 없지만, 혹시 모르니 비활성화
sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

2.2 커널 모듈 / 네트워크 설정

cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay
sudo modprobe br_netfilter

cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                 = 1
EOF
sudo sysctl --system

2.3 containerd 설치

kubeadm 클러스터는 Docker 가 필요 없습니다. containerd 만 설치합니다.

sudo apt install -y containerd

sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml > /dev/null
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd
sudo systemctl enable containerd

# true 로 바뀌었는지 확인
grep SystemdCgroup /etc/containerd/config.toml

2.4 kubelet / kubeadm / kubectl 설치

VER=v1.34
curl -fsSL https://pkgs.k8s.io/core:/stable:/$VER/deb/Release.key | sudo gpg --dearmor --yes -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/$VER/deb/ /" \
  | sudo tee /etc/apt/sources.list.d/kubernetes.list

sudo apt update
sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

2.5 클러스터 초기화

sudo kubeadm init --pod-network-cidr=10.244.0.0/16

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

# 네트워크 플러그인 (Flannel)
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

# 단일 노드이므로 컨트롤 플레인에도 파드 배치 허용 (끝의 - 는 오타 아님)
kubectl taint nodes --all node-role.kubernetes.io/control-plane-

노드가 Ready 가 되면 완료입니다.

kubectl get nodes

초기화에 실패했다면 sudo kubeadm reset -f 후 다시 실행합니다.
로그는 sudo journalctl -u kubelet -f 로 확인합니다.

2.6 Helm 설치

ArgoCD 최초 설치(부트스트랩)에만 사용합니다.

curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-4 | bash
helm version

helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
helm search repo argo/argo-cd     # CHART VERSION 확인

3. Git 저장소 작성 (로컬 PC)

GitHub 에 Private 저장소 k8s-gitops-aws 를 만들고, 아래 파일들을 작성합니다.
이하 <YOUR_ID> 는 본인 GitHub 아이디로 바꿉니다.

3.1 values/argocd/values.yaml

server:
  service:
    type: NodePort
    nodePortHttp: 30080
    nodePortHttps: 30443

# 단일 사용자 환경에서는 불필요 → 메모리 절약
dex:
  enabled: false
notifications:
  enabled: false

3.2 nginx 차트: charts/nginx

nginx 용 최소 Helm 차트입니다. 차트 기본값(charts/nginx/values.yaml)과 환경 설정(values/nginx/values.yaml)을 분리해 두면,
나중에 환경을 추가하거나 차트를 다른 저장소로 옮길 때 values 만 추가하면 됩니다.

charts/nginx/Chart.yaml

apiVersion: v2
name: nginx
description: nginx web server
type: application
version: 0.1.0
appVersion: "1.29"

charts/nginx/values.yaml (차트 기본값)

replicaCount: 1

image:
  repository: nginx
  tag: ""              # 비우면 appVersion 사용

service:
  type: ClusterIP
  port: 80
  nodePort: null

charts/nginx/templates/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}
  labels:
    app: {{ .Release.Name }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app: {{ .Release.Name }}
    spec:
      containers:
        - name: nginx
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          ports:
            - containerPort: 80

charts/nginx/templates/service.yaml

apiVersion: v1
kind: Service
metadata:
  name: {{ .Release.Name }}
spec:
  type: {{ .Values.service.type }}
  selector:
    app: {{ .Release.Name }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: 80
      {{- if and (eq .Values.service.type "NodePort") .Values.service.nodePort }}
      nodePort: {{ .Values.service.nodePort }}
      {{- end }}

3.3 values/nginx/values.yaml (이 클러스터의 실제 설정)

replicaCount: 2

service:
  type: NodePort
  nodePort: 31405

3.4 apps/nginx.yaml

ArgoCD 와 같은 multi-source 형태로 작성합니다. 차트와 values 가 같은 저장소에 있지만 형태를 통일해 두면,
나중에 차트를 다른 곳으로 옮겨도 첫 번째 source 만 바꾸면 됩니다.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: nginx
  namespace: argocd
  finalizers:
    - resources-finalizer.argocd.argoproj.io
spec:
  project: default
  sources:
    # ① 차트: 내 저장소의 charts/nginx
    - repoURL: https://github.com/<YOUR_ID>/k8s-gitops-aws.git
      targetRevision: main
      path: charts/nginx
      helm:
        releaseName: nginx
        valueFiles:
          - $values/values/nginx/values.yaml
    # ② values: 내 저장소 (ref 이름이 위의 $values 가 됨)
    - repoURL: https://github.com/<YOUR_ID>/k8s-gitops-aws.git
      targetRevision: main
      ref: values
  destination:
    server: https://kubernetes.default.svc
    namespace: default
  syncPolicy:
    automated:
      prune: true      # Git 에서 지운 리소스는 클러스터에서도 삭제
      selfHeal: true   # kubectl 로 직접 바꿔도 Git 상태로 되돌림

3.5 apps/argocd.yaml (ArgoCD 가 자기 자신을 관리)

차트는 Helm 저장소에서, values 는 내 Git 저장소에서 가져오는 multi-source 방식입니다.
releaseName, namespace, 차트 버전, values 가 4.1 의 helm install 과 같아야 충돌 없이 인수됩니다.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: argocd
  namespace: argocd
  # finalizer 없음: Application 을 실수로 지워도 ArgoCD 는 남도록
spec:
  project: default
  sources:
    - repoURL: https://argoproj.github.io/argo-helm
      chart: argo-cd
      targetRevision: 10.9.5          # helm search repo 결과로 변경
      helm:
        releaseName: argocd
        valueFiles:
          - $values/values/argocd/values.yaml
    - repoURL: https://github.com/<YOUR_ID>/k8s-gitops-aws.git
      targetRevision: main
      ref: values                     # 위의 $values 가 이 저장소를 가리킴
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated:
      prune: false
      selfHeal: true
    syncOptions:
      - ServerSideApply=true          # ArgoCD CRD 크기 제한 회피

3.6 bootstrap/root-app.yaml (App of Apps)

apps/ 디렉터리를 바라보는 루트 Application 입니다. 이것 하나만 수동으로 적용합니다.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: root
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/<YOUR_ID>/k8s-gitops-aws.git
    targetRevision: main
    path: apps
  destination:
    server: https://kubernetes.default.svc
    namespace: argocd
  syncPolicy:
    automated:
      prune: true
      selfHeal: true

3.7 push

git add .
git commit -m "argocd + nginx"
git push origin main

4. ArgoCD 설치 및 적용 (EC2)

4.1 GitHub 토큰 발급

GitHub → Settings → Developer settings → Fine-grained tokens 에서 토큰을 발급합니다.

  • Repository access: k8s-gitops-aws 만 선택
  • Permissions: Contents → Read-only

4.2 저장소 clone 후 ArgoCD 설치

Git 의 values 파일을 그대로 사용해서 설치합니다.

git clone https://<YOUR_ID>:<GITHUB_TOKEN>@github.com/<YOUR_ID>/k8s-gitops-aws.git
cd k8s-gitops-aws

helm install argocd argo/argo-cd \
  --namespace argocd --create-namespace \
  --version 10.9.5 \
  -f values/argocd/values.yaml

kubectl -n argocd get pods -w     # 모두 Running 이 될 때까지 대기

4.3 Private 저장소 등록

ArgoCD 가 Private 저장소를 읽을 수 있도록 인증 정보를 Secret 으로 등록합니다.
이 Secret 은 Git 에 커밋하지 않습니다.

kubectl -n argocd create secret generic repo-k8s-gitops-aws \
  --from-literal=type=git \
  --from-literal=url=https://github.com/<YOUR_ID>/k8s-gitops-aws.git \
  --from-literal=username=<YOUR_ID> \
  --from-literal=password=<GITHUB_TOKEN>

kubectl -n argocd label secret repo-k8s-gitops-aws argocd.argoproj.io/secret-type=repository

4.4 루트 Application 적용

kubectl apply -f bootstrap/root-app.yaml

잠시 후 모두 Synced / Healthy 가 되면 완료입니다.

kubectl -n argocd get applications
------------------------------------
NAME     SYNC STATUS   HEALTH STATUS
argocd   Synced        Healthy
nginx    Synced        Healthy
root     Synced        Healthy

4.5 접속 확인

# ArgoCD 초기 비밀번호 (사용자: admin)
kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d; echo
  • ArgoCD : https://<EC2_PUBLIC_IP>:30443/ (자체 서명 인증서 경고는 무시)
  • nginx : http://<EC2_PUBLIC_IP>:31405/

로그인 후 User Info → Update Password 에서 비밀번호를 바꾸고,
kubectl -n argocd delete secret argocd-initial-admin-secret 으로 초기 비밀번호 Secret 을 삭제합니다.


5. 운영: 이제부터는 Git 만 수정

nginx 레플리카 변경

vi values/nginx/values.yaml            # replicaCount: 3
git commit -am "nginx replicas 3"
git push

push 전에 결과 미리 보기

ArgoCD 와 같은 차트 + 같은 values 이므로, 로컬 결과가 그대로 배포됩니다.

helm template nginx charts/nginx -f values/nginx/values.yaml

ArgoCD 버전 업그레이드

vi apps/argocd.yaml                    # targetRevision 만 변경
git commit -am "argo-cd upgrade"
git push

ArgoCD 는 기본 3분 주기로 Git 을 확인합니다. 바로 반영하려면 UI 에서 Refresh 를 누릅니다.

주의사항

  • kubectl edit, kubectl scale 로 직접 수정하면 selfHeal 이 되돌립니다.
  • 설치 후 helm upgrade argocd ... 는 사용하지 않습니다. 업그레이드는 apps/argocd.yaml 로 합니다.
  • 비밀번호·토큰 같은 비밀값은 Git 에 넣지 않습니다.

6. 정리

단계 작업 위치
1 EC2 생성, 보안 그룹 설정 AWS 콘솔
2 containerd + kubeadm 설치, 클러스터 초기화 EC2
3 Git 저장소 작성 후 push 로컬 PC
4 helm install argocd → 저장소 등록 → root-app 적용 EC2
5 이후 변경은 Git push 만 로컬 PC

EC2 를 새로 만들어도 2장 → 4장만 다시 하면 나머지는 Git 에 있는 그대로 복원됩니다.

답글 남기기