Kubernetes – AWS EC2 단일 노드에 ArgoCD + nginx 구성하기 (GitOps, Private 저장소)
AWS EC2 인스턴스 한 대에 kubeadm 으로 쿠버네티스를 설치하고, ArgoCD 와 nginx 만 올리는 최소 구성입니다.
모든 설정은 GitHub Private 저장소에 두고, 배포는 ArgoCD 가 Git 을 보고 수행합니다.
EC2 는 메모리가 4GB 이상이어야 하고, 우분투 OS 여야 합니다.
수동으로 하는 작업은 다음 두 가지뿐입니다.
helm install로 ArgoCD 최초 설치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 에 있는 그대로 복원됩니다.