1. ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ํฌํฌ ํ•˜๊ธฐ

  # ํ˜„์žฌ ๊ณ„์ • ๋ฐ ์—ฐ๊ฒฐ ์ƒํƒœ ํ™•์ธ
gh auth status

# ๊ณ„์ • ์—ฐ๊ฒฐ
gh auth login 

# ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ Fork with Clone
gh repo fork https://github.com/dangtong76/istory-web-k8s.git --clone=false
git clone https://github.com/<your-id>/istory-web-k8s.git istory-web
# ํ”Œ๋žซํผ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ Fork with Clone
gh repo fork https://github.com/dangtong76/istory-platform-k8s.git --clone=false
git clone https://github.com/<your-id>/istory-platform-k8s.git istory-platform
  
  ### - ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑํ•˜๊ธฐ
labs/istory-platform ์—์„œ ์ˆ˜ํ–‰
```bash
mkdir -p aws-eks/base/istory-app
mkdir -p aws-eks/base/istory-db
mkdir -p aws-eks/base/istory-tools
mkdir -p aws-eks/overlay/aws-dev
mkdir -p aws-eks/overlay/aws-prod
mkdir -p aws-eks/overlay/local-dev
  

- ํŒŒ์ผ ์ƒ์„ฑํ•˜๊ธฐ

labs/istory-platform ์—์„œ ์ˆ˜ํ–‰

  touch aws-eks/base/istory-app/istory-app-config.yml
touch aws-eks/base/istory-app/istory-app-deploy.yml
touch aws-eks/base/istory-app/istory-app-lb.yml
touch aws-eks/base/istory-app/kustomization.yml
touch aws-eks/base/istory-db/istory-db-pod.yml
touch aws-eks/base/istory-db/istory-db-lb.yml
touch aws-eks/base/istory-db/istory-db-pvc.yml
touch aws-eks/base/istory-db/istory-db-sc.yml
touch aws-eks/base/istory-db-init-config.yml
touch aws-eks/base/istory-db/kustomization.yml
touch aws-eks/base/istory-tools/busybox.yml
touch aws-eks/base/istory-tools/kustomization.yml
touch aws-eks/overlay/aws-dev/kustomization.yml
touch aws-eks/overlay/aws-dev/patch-deploy.yml
touch aws-eks/overlay/aws-dev/patch-lb-annotations.yml
touch aws-eks/overlay/aws-dev/.env.secret
  

- ๊ฐœ๋ฐœ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์ƒ์„ฑ

  kubectl create ns istory-dev
  

3. ๋„์ปค ํŒŒ์ผ ๋นŒ๋“œ ๋ฐ ์—…๋กœ๋“œ

- ๋„์ปค ํŒŒ์ผ์ƒ์„ฑ

ํŒŒ์ผ์œ„์น˜ : xinfra/docker/Dockerfile

  FROM eclipse-temurin:21-jdk-alpine
VOLUME /tmp
RUN addgroup -S istory && adduser -S istory -G istory
USER istory
WORKDIR /home/istory
COPY *.jar /home/istory/istory.jar
ENTRYPOINT ["java","-jar","/home/istory/istory.jar"]
  

- ์ž๋ฐ” ๋นŒ๋“œ (Gradle)

gradlew ๊ฐ€ ์žˆ๋Š” ๋””๋ ‰ํ† ๋ฆฌ ์œ„์น˜์—์„œ ์‹คํ–‰ ํ•ฉ๋‹ˆ๋‹ค.

  ./gradlew build -x test
  

๋นŒ๋“œ ํ›„์—๋Š” istory-web-k8s/build/libs/springbootdeveloper-0.0.1-SNAPSHOT.jar ์ด ์ƒ์„ฑ ๋ฉ๋‹ˆ๋‹ค.
์ด ํŒŒ์ผ์„ ๋„์ปค build ๋ฅผ ์œ„ํ•ด์„œ istory-web-k8s/xinfra/docker ๋””๋ ‰ํ† ๋ฆฌ ์•ˆ์— ๋ณต์‚ฌ ํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ตณ์ด ๋ณต์‚ฌํ•˜์ง€ ์•Š์•„๋„ build.gradle ํŒŒ์ผ์—๋Š” ๋นŒ๋“œ๊ฐ€ ์„ฑ๊ณตํ•  ๊ฒฝ์šฐ ์ž๋™ ๋ณต์‚ฌํ•˜๋Š” ๊ตฌ๋ฌธ์ด ๋“ค์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

  task copyJarToBin(type: Copy) {
    from "build/libs/springbootdeveloper-0.0.1-SNAPSHOT.jar"
    into "xinfra/docker/"
}
  

๋งŒ์•ฝ ํŒŒ์ผ์ด ์—†๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ˆ˜๋™์œผ๋กœ ๋ณต์‚ฌ ํ•˜์„ธ์š”!

  cp build/libs/springbootdeveloper-0.0.1-SNAPSHOT.jar xinfra/docker/
  

- ๋„์ปค ํŒŒ์ผ ๋นŒ๋“œ ๋ฐ ์—…๋กœ๋“œ

  # xinfra/docker ์—์„œ ์ˆ˜ํ–‰
# ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ๋นŒ๋“œ 
docker build -t <your-docker-hub-id>/istory:1 .
  
  # ๋ฉ€ํ‹ฐ ํ”Œ๋žซํผ ๋นŒ๋“œ 
docker buildx build  --platform linux/amd64,linux/arm64  -t <your-dockerhub-id>/<image-name> --push .
  
  # latest ํƒœ๊ทธ ๋งŒ๋“ค๊ธฐ
docker tag <your-docker-hub-id>/istory:1 <your-docker-hub-id>/istory:latest

# Docker hub ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ๋กœ๊ทธ์ธ
docker login --username <your-docker-hub-id>

# ์—…๋กœ๋“œ
docker push <your-docker-hub-id>/istory:1
docker push <your-docker-hub-id>/istory:latest
  

4. istory-app base ์ƒ์„ฑ

- istory-app-config.yml

์œ„์น˜ : xinfra/aws-eks/base/istory-app

  apiVersion: v1
kind: ConfigMap
metadata:
  name: istory-app-config
data:
  spring.datasource.url: 'jdbc:mysql://istory-db-lb:3306/istory'
  spring.datasource.driver-class-name: 'com.mysql.cj.jdbc.Driver'
  spring.jpa.database-platform: 'org.hibernate.dialect.MySQLDialect'
  spring.jpa.hibernate.ddl-auto: 'update'
  spring.jpa.show-sql: 'true'
  spring.application.name: 'USER-SERVICE'
  

- istory-app-deploy.yml

์œ„์น˜ : xinfra/aws-eks/base/istory-app
์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ์ด๋ฆ„์„ ๋ฐ˜๋“œ์‹œ ์ž์‹ ์˜ Docker Hub ๊ณ„์ •์œผ๋กœ ๋ณ€๊ฒฝ ํ•ด์•ผํ•จ.

  apiVersion: apps/v1
kind: Deployment
metadata:
  name:  istory-app-deploy
  labels:
    app:  istory-app
spec:
  selector:
    matchLabels:
      app: istory-app
  replicas: 3
  template:
    metadata:
      labels:
        app: istory-app
    spec:
      initContainers:
        - name: check-mysql-ready
          image: mysql:8.0
          env:
            - name: MYSQL_USER
              valueFrom:
                secretKeyRef:
                  name: istory-db-secret
                  key: MYSQL_USER
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: istory-db-secret
                  key: MYSQL_PASSWORD
          command: ['sh',
                    '-c',
                    'until mysqladmin ping -u ${MYSQL_USER} -p${MYSQL_PASSWORD} -h istory-db-lb; do echo waiting for database; sleep 2; done;']
      containers:
        - name: istory
          image: <your-docker-hub-account-id>/istory:latest # ๋ณ€๊ฒฝํ•„์š”
          envFrom:
            - configMapRef:
                name: istory-app-config
          env:
            - name: spring.datasource.password
              valueFrom:
                secretKeyRef:
                  name: istory-db-secret
                  key: MYSQL_PASSWORD
            - name: spring.datasource.username
              valueFrom:
                secretKeyRef:
                  name: istory-db-secret
                  key: MYSQL_USER
          readinessProbe:
            httpGet:
              path: /
              port: 8080
            initialDelaySeconds: 60
            timeoutSeconds: 3
            successThreshold: 2
            failureThreshold: 3
            periodSeconds: 20
          ports:
            - containerPort:  3306
              name: istory
      volumes:
        - name: application-config
          configMap:
            name: istory-app-config
      restartPolicy: Always
  

- istory-app-lb.yml

์œ„์น˜ : xinfra/aws-eks/base/istory-app

  apiVersion: v1
kind: Service
metadata:
  name: istory-app-lb
spec:
  type: LoadBalancer
  selector:
    app: istory-app
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 800
  ports:
    - name: istory-app-lb
      protocol: TCP
      port: 80
      targetPort: 8080
  

- kustomization.yml

์œ„์น˜ : xinfra/aws-eks/base/istory-app

  resources:
  - istory-app-config.yml
  - istory-app-deploy.yml
  - istory-app-lb.yml
  

5. istory-db base ์ƒ์„ฑ

- istory-db-lb.yml

์œ„์น˜ : xinfra/aws-eks/base/istory-db/

  apiVersion: v1
kind: Service
metadata:
  name: istory-db-lb
spec:
  selector:
    app: mysql
  ports:
    - name: mysql-db-lb
      protocol: TCP
      port: 3306
  

- istory-db-pod.yml

์œ„์น˜ : xinfra/aws-eks/base/istory-db/

  apiVersion: v1
kind: Pod
metadata:
  name: istory-db
  labels:
    app: mysql
spec:
  containers:
    - image: mysql:5.6
      name: mysql
      envFrom:
        - secretRef:
            name: istory-db-secret
      ports:
        - containerPort: 3306
          name: mysql
      volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
        - name: initdb
          mountPath: /docker-entrypoint-initdb.d # mysql ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์‹คํ–‰๋˜๋ฉด ์ตœ์ดˆ๋กœ ์ž๋™ ์‹คํ–‰๋˜๋Š” ๋””๋ ‰ํ† ๋ฆฌ 
  volumes:
    - name: mysql-persistent-storage
      persistentVolumeClaim:
        claimName: mysql-pv-claim
    - name: initdb
      configMap:
        name: mysql-initdb-config
  

- istory-db-pvc.yml

์œ„์น˜ : xinfra/aws-eks/base/istory-db

  apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
  labels:
    app: mysql
spec:
  storageClassName: gp2-persistent
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  

- istory-db-sc.yml

์œ„์น˜ : xinfra/aws-eks/base/istory-db

  apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp2-persistent
provisioner: kubernetes.io/aws-ebs
reclaimPolicy: Retain
parameters:
  type: gp2
  fsType: ext4
volumeBindingMode: WaitForFirstConsumer
  

- istory-db-init-config.yml

์œ„์น˜ : xinfra/aws-eks/base/istory-db

  apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp2-persistent
provisioner: kubernetes.io/aws-ebs
reclaimPolicy: Retain
parameters:
  type: gp2
  fsType: ext4
volumeBindingMode: WaitForFirstConsumer
  

kustomization.yml

์œ„์น˜ : xinfra/aws-eks/base/istory-db

  resources:
  - istory-db-pod.yml
  - istory-db-lb.yml
  - istory-db-pvc.yml
  - istory-db-sc.yml
  - istory-db-init-config.yml
  

6. istroy-tools base ์ƒ์„ฑ

- busybox.yml

์œ„์น˜ : xinfra/aws-eks/base/istory-tools

  apiVersion: v1
kind: Pod
metadata:
  name: ubuntu-pod
spec:
  containers:
    - name: ubuntu-container
      image: ubuntu
      command: ["sleep", "infinity"]
  

- kustomization.yml

์œ„์น˜ : xinfra/aws-eks/base/istory-tools

  resources:
  - busybox.yml
  

7. aws-dev overlay ์ƒ์„ฑ

์œ„์น˜ : xinfra/aws-eks/overlay/aws-dev

- patch-deploy.yml

  apiVersion: apps/v1
kind: Deployment
metadata:
  name: istory-app-deploy
  annotations:
    istory.io/env: dev
    istory.io/tier: backend-app
    istory.io/infra: aws
spec:
  replicas: 1
  

์œ„์น˜ : xinfra/aws-eks/overlay/aws-dev

- patch-lb-annotaions.yml

  apiVersion: v1
kind: Service
metadata:
  name: istory-lb
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: external
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
    service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
    istory.io/infra: aws
    istory.io/env: dev
    istory.io/tier: app-lb
  

- kustomization.yml

์œ„์น˜ : xinfra/aws-eks/overlay/aws-dev

  • kustomiztion.yml ์—์„œ newTag ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, kustomize edit ๋ช…๋ น์„ ํ†ตํ•ด์„œ ์ด๋ฏธ์ง€๋ฅผ ๋ณ€๊ฒฝ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • kustomize ์—์„œ๋Š” secretGenerator, configMapGenerator ๋ฅผ ์ œ๊ณต ํ•ฉ๋‹ˆ๋‹ค. ์ œ๋„ˆ๋ ˆ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด .env ํŒŒ์ผ์„ ํ†ตํ•ด ์ •๋ณด๋ฅผ ๋งŒ๋“ค๋ฉด kustomize๊ฐ€ ConfigMap๊ณผ Secret ๋ฅผ ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.

  resources:
  - ../../base/istory-app
  - ../../base/istory-db

namespace: istory-dev

patches:
  - path: patch-lb-annotations.yml
    target:
      kind: Service
      name: istory-app-lb

  - path: patch-deploy.yml
    target:
      kind: Deployment
      name: istory-app-deploy

secretGenerator:
  - name: istory-db-secret
    envs:
      - .env.secret
    # ์•„๋ž˜ ์–‘์‹์œผ๋กœ .env.secret ํŒŒ์ผ์„ ๋งŒ๋“œ์„ธ์š”
    # MYSQL_USER=myuser
    # MYSQL_PASSWORD=myuserpassword
    # MYSQL_ROOT_PASSWORD=myrootpassword

images:
  # base/istory-app/istory-app-deploy.yml ๋‚ด์˜ ์ด๋ฏธ์ง€ ์ด๋ฆ„๊ณผ ๋™์ผํ•ด์•ผ ๋ณ€๊ฒฝ๋จ
  - name: <your-docker-hub-account-id>/istory # ๋ณ€๊ฒฝํ•„์š” 
    newTag: latest

generatorOptions:
  disableNameSuffixHash: true
  

- .env.secret ํŒŒ์ผ ์ž‘์„ฑ

  # ์•„๋ž˜ ์–‘์‹์œผ๋กœ .env.secret ํŒŒ์ผ์„ ๋งŒ๋“œ์„ธ์š”
MYSQL_USER=myuser
MYSQL_PASSWORD=myuserpassword
MYSQL_ROOT_PASSWORD=myrootpassword
MYSQL_DATABASE=dbname
  

- kustomize ์„ค์น˜

  • ์‹คํ–‰ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ
  curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"  | bash
  
  • PATH ๊ฑธ๋ ค์žˆ๋Š” ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ด๋™
  mv kustomize /usr/sbin/
  
  • ๋ช…๋ น์–ด ์‹คํ–‰ ํ•ด๋ณด๊ธฐ
  kustomize
  

- kustomize ๋นŒ๋“œ ํ•ด๋ณด๊ธฐ

  • ๋นŒ๋“œ๊ฐ€ ์—๋Ÿฌ ์—†์ด ์ •์ƒ์ ์ธ ์ถœ๋ ฅ์„ ์ƒ์„ฑํ•˜๋ฉด OK!
  kustomize build overlay/aws-dev
  

- ๊ธฐํƒ€ ์ฐธ๊ณ  ์‚ฌํ•ญ

kustomize ๋ช…๋ น์–ด๋กœ ์ด๋ฏธ์ง€๋ฅผ ๋ณ€๊ฒฝ ํ• ๋•Œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋ช…๋ น์–ด ์‚ฌ์šฉ

  # ์ปค๋ฐ‹ ํ•ด์‹œ๋ฅผ ์ด์šฉํ•œ ํƒœ๊น… ๋ฐฉ๋ฒ•
kustomize edit set image istory=dagntong76/istory:${{ github.sha }}
# ์›Œํฌํ”Œ๋กœ์šฐ ์ˆ˜ํ–‰ ํšŸ์ˆ˜๋ฅผ ์ด์šฉํ•œ ํƒœ๊น… ๋ฐฉ๋ฒ• 
kustomize edit set image istory=dagntong76/istory:${{ github.run_number }}
  
  • patch-deploy.yml ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ๊ธฐ
    ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ๋ถ€๋ถ„์„ ์ž์‹ ์˜ Docker Hub ๊ณ„์ •์˜ ์ด๋ฏธ์ง€๋กœ ๋ณ€๊ฒฝ
  apiVersion: apps/v1
kind: Deployment
metadata:
  name: istory-app-deploy
  annotations:
    istory.io/env: dev
    istory.io/tier: backend-app
    istory.io/infra: aws
spec:
  replicas: 1
  template:
    spec:
      containers:
        - name: istory
          image: <your-docker-hub-account-id>/istory:latest # ๋ณ€๊ฒฝํ•„์š”
  

์ด ๊ฒฝ์šฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด workflow ์—์„œ SED ๋ฅผ ์‚ฌ์šฉ

  sed -i "s|image: .*|image: dangtong76/istory:${{ github.sha }}|" overlay/aws-dev/patch-deploy.yml
  

8. ArgoCD ์„œ๋ฒ„ ์„ค์น˜

  kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
  

9. ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ ์ถ”๊ฐ€ํ•˜๊ธฐ

  # Patch์ผ ๊ฒฝ์šฐ Annotation์ด ์—†์–ด์„œ Classic LB๊ฐ€ ์ƒ์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์™ธ๋ถ€ ์ ‘์† ๊ฐ€๋Šฅ
# ์ผ๋ฐ˜์ ์œผ๋กœ Patch๊ฐ€ ์•„๋‹ˆ๋ผ Create์ผ ๊ฒฝ์šฐ Network LB ์ƒ์„ฑ๋˜๊ณ , ์ด๋•Œ๋Š” Annotation ์žˆ์–ด์•ผํ•จ.
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}'
  

10. ArgoCD CLI ์„ค์น˜

์›น VSCODE IDE๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์ด๋ฏธ ์„ค์น˜ ๋˜์–ด ์žˆ์Œ

- Linux

  # latest Version
curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
rm argocd-linux-amd64

# stable Version
VERSION=$(curl -L -s https://raw.githubusercontent.com/argoproj/argo-cd/stable/VERSION)
curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/download/v$VERSION/argocd-linux-amd64
sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd
rm argocd-linux-amd64
  

- Windows

  $version = (Invoke-RestMethod https://api.github.com/repos/argoproj/argo-cd/releases/latest).tag_name
$url = "https://github.com/argoproj/argo-cd/releases/download/" + $version + "/argocd-windows-amd64.exe"
$output = "argocd.exe"

Invoke-WebRequest -Uri $url -OutFile $output
  

- Mac

  brew install argocd
  

11. Argocd ์„œ๋ฒ„ ์„ค์ •

- Admin ํŒจ์Šค์›Œ๋“œ ์•Œ์•„๋‚ด๊ธฐ

  argocd admin initial-password -n argocd
  

- ์ ‘์† Endpoint ์•Œ์•„๋‚ด๊ธฐ

  kubectl get svc argocd-server -n argocd

###### ์ถœ๋ ฅ ์˜ˆ์‹œ ######
NAME            TYPE           CLUSTER-IP      EXTERNAL-IP                                                                    PORT(S)                      AGE
argocd-server   LoadBalancer   172.20.21.170   a7eb417c510ec4551933abc911356e6e-1770617535.ap-northeast-2.elb.amazonaws.com   80:31698/TCP,443:31412/TCP   103s
  

- Argocd CLI ๋กœ๊ทธ์ธ

  argocd login <EXTERNAL-IP>

###### ์ถœ๋ ฅ ์˜ˆ์‹œ ######
WARNING: server certificate had error: tls: failed to verify certificate: x509: certificate signed by unknown authority. Proceed insecurely (y/n)? y
Username: admin
Password: 
'admin:login' logged in successfully
Context 'a7eb417c510ec4551933abc911356e6e-1770617535.ap-northeast-2.elb.amazonaws.com' updated
  

- ์ƒˆ๋กœ์šด ํŒจ์Šค์›Œ๋“œ๋กœ ๋ณ€๊ฒฝ

  argocd account update-password --current-password <ํ˜„์žฌํŒจ์Šค์›Œ๋“œ> --new-password <์ƒˆ๋กœ์šดํŒจ์Šค์›Œ๋“œ>
  

12. ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ฐ˜ ์„ค์ •

- ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์„ค์ •

  • ์›น ๋ฉ”๋‰ด : Settings โ†’ Repositories โ†’ CONNECT REPO
    ์„ค์ • ํ•ญ๋ชฉ๊ฐ’์„ค๋ช…
    connection methodVIA HTTPSGit ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์ ‘์† ๋ฐฉ์‹
    Typegit๋ฆฌํฌ์ง€ํ† ๋ฆฌ ํƒ€์ž…(git
    Nameistory-dev์ฐธ์กฐ ์ด๋ฆ„
    ProjectDefaultGit ์˜ ๋ธŒ๋ Œ์น˜ ์ด๋ฆ„
    Repository URLhttps://github.com/<github-id>/istory-platform.gitPlatform ๋ฆฌํฌ์ง€ํ† ๋ฆฌ URL

  • ์„ค์ •ํ™”๋ฉด ์ฐธ์กฐ
    argocd ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์„ค์ •

- ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค์ •

  • ์›น ๋ฉ”๋‰ด : Application โ†’ NEW APP
์„ค์ • ํ•ญ๋ชฉ๊ฐ’์„ค๋ช…
Application Nameistory-dev-
Project Namedefault-
Repository URLhttps://github.com/<github-id>/istory-platform.git-
Pathoverlayaws-dev
Cluster URLhttps://kubernetes.default.svc-
Namespaceistory-dev-

  • ์„ค์ • ํ™”๋ฉด ์ฐธ์กฐ
    argocd ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค์ •1

    argocd ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค์ •2

- ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‹œํฌ๋ฆฟ ์ƒ์„ฑ ํ•˜๊ธฐ (.env.secret ์ƒ์„ฑํ•˜์ง€ ์•Š์•—์„ ๊ฒฝ์šฐ)

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ณ„์ • ๋ฐ ํŒจ์Šค์›Œ๋“œ๋Š” Github Action Secret์„ ์ด์šฉํ•ด์„œ ๋™์ ์œผ๋กœ ์ƒ์„ฑ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ตœ์ดˆ์— ์‹ฑํฌ ์‹œ์—๋Š” ์ง์ ‘ K8s Secret ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•จ.
Workflow ์—์„œ๋Š” Github Action Secret ์„ ์ฐธ์กฐํ•ด์„œ ๊ณ„์† ์—…๋ฐ์ดํŠธ(kubectl apply …) ๊ฐ€๋Šฅํ•˜๋„๋ก ํ•ด์•ผ ํ•จ.

  kubectl create secret generic istory-db-secret \
--namespace istory-dev \
--from-literal=MYSQL_USER=user \
--from-literal=MYSQL_PASSWORD=user12345 \ 
--from-literal=MYSQL_DATABASE=istory \
--from-literal=MYSQL_ROOT_PASSWORD=admin123
  

- Sync ํ•˜๊ธฐ

  • ์›น ๋ฉ”๋‰ด : Application โ†’ SYNC โ†’ Synchronize

13. ๋ช…๋ น์–ด ๊ธฐ๋ฐ˜ ์„ค์ • (์ถ”ํ›„ ์—…๋ฐ์ดํŠธ ์˜ˆ์ •)

์ถ”ํ›„ ์—…๋ฐ์ดํŠธ ์˜ˆ์ • …

14. ์›Œํฌํ”Œ๋กœ์šฐ ํ™˜๊ฒฝ ์„ค์ •

- ์ž๋ฐ” ์†Œ์Šค ์ˆ˜์ •

Github Action Workflow๋ฅผ ํ†ตํ•ด ๋นŒ๋“œ๋œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์†Œ์Šค์— ๋ฒ„์ „์„ ์ถ”๊ฐ€ ํ•ฉ๋‹ˆ๋‹ค.
ํŒŒ์ผ ์œ„์น˜ : src/main/resources/templates/login.html

์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋กœ๊ทธ์ธ์„ ํ•ด์ฃผ์„ธ์š”! ๋’ท ๋ถ€๋ถ„์— ๋ฐฐํฌ ๋ฒ„์ „ ์ถ”๊ฐ€ V4.0

  <!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>๋กœ๊ทธ์ธ</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">

    <style>
        .gradient-custom {
            background: linear-gradient(to right, rgba(106, 17, 203, 1), rgba(37, 117, 252, 1))
        }
    </style>
</head>
<body class="gradient-custom">
<section class="d-flex vh-100">
    <div class="container-fluid row justify-content-center align-content-center">
        <div class="card bg-dark" style="border-radius: 1rem;">
            <div class="card-body p-5 text-center">
                <h2 class="text-white">LOGIN</h2>
                <p class="text-white-50 mt-2 mb-5">์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋กœ๊ทธ์ธ์„ ํ•ด์ฃผ์„ธ์š”! V4.0</p>

                <div class = "mb-2">
                    <form action="/login" method="POST">
                        <input type="hidden" th:name="${_csrf?.parameterName}" th:value="${_csrf?.token}" />
                        <div class="mb-3">
                            <label class="form-label text-white">Email address</label>
                            <input type="email" class="form-control" name="username">
                        </div>
                        <div class="mb-3">
                            <label class="form-label text-white">Password</label>
                            <input type="password" class="form-control" name="password">
                        </div>
                        <button type="submit" class="btn btn-primary">Submit</button>
                    </form>

                    <button type="button" class="btn btn-secondary mt-3" onclick="location.href='/signup'">ํšŒ์›๊ฐ€์ž…</button>
                </div>
            </div>
        </div>
    </div>
</section>
</body>
</html>
  

- Github ํ† ํฐ์ƒ์„ฑ

์›Œํฌํ”Œ๋กœ์šฐ ์—์„œ ์‚ฌ์šฉํ•  ACCESS TOKEN ๋“ค์„ ๊ฐ ์‚ฌ์ดํŠธ์— ๋ฐฉ๋ฌธํ•ด์„œ ์ƒ์„ฑ ํ•ฉ๋‹ˆ๋‹ค.

  • Github Token ์ƒ์„ฑ
    Github ์‚ฌ์ดํŠธ์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ํ† ํฐ์„ ์ƒ์„ฑ ํ•ฉ๋‹ˆ๋‹ค.
    Profile โ†’ settings โ†’ < > Developer settings โ†’ ๐Ÿ”‘ Personal access tokens โ†’ Fine-grained tokens โ†’ Generate new token

  • ์ƒ์„ธ ์ž…๋ ฅ ํ•ญ๋ชฉ

    ์ž…๋ ฅ ํ•ญ๋ชฉ์ž…๋ ฅ ๊ฐ’
    Token namepersonal_access_token
    Repository accessAll repositories ์— ์ฒดํฌ
    Repository PermissionRead and Write for Actions, Administration, Codepsaces, Contents, Metadata, Pull requests, Secrets, Variables, Workflows

- Docker Hub ํ† ํฐ ์ƒ์„ฑ

๋„์ปค ํ—ˆ๋ธŒ ์‚ฌ์ดํŠธ ์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ACCESS TOKEN์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
Profile โ†’ Account Setting โ†’ ๐Ÿ”‘ Personal access tokens โ†’ Generate new token

  • ์ƒ์„ธ ์ž…๋ ฅ ํ•ญ๋ชฉ
    ์ž…๋ ฅ ํ•ญ๋ชฉ์ž…๋ ฅ ๊ฐ’
    Access token descriptionGithub Workflow TOKEN
    Expiration date30 days
    Access permissionsRead & Write

- ์›Œํฌ ํ”Œ๋กœ์šฐ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ

istory-web-k8s ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์ˆ˜ํ–‰

  mkdir -p .github/workflows
  

- create-secret.sh ์ž‘์„ฑ

ํŒŒ์ผ ์œ„์น˜ : .github/workflows/create-secret.sh

  gh api -X PUT repos/<your-github-id>/istory-web-k8s/environments/k8s-dev  --silent
gh secret set DATABASE_URL --env k8s-dev --body "jdbc:mysql:istory-db-lb:3306/istory"
gh secret set MYSQL_DATABASE --env k8s-dev --body "istory"
gh secret set MYSQL_USER --env k8s-dev --body "user"
gh secret set MYSQL_PASSWORD --env k8s-dev --body "user12345"
gh secret set MYSQL_ROOT_PASSWORD --env k8s-dev --body "admin123"

gh secret set DOCKER_USERNAME --env k8s-dev --body "<your-docker-hub-id>"
gh secret set DOCKER_TOKEN --env k8s-dev --body "<your-docker-hub-token>"

gh secret set GIT_ACCESS_TOKEN --env k8s-dev --body "<your-github-access-token>"
gh secret set GIT_USERNAME --env k8s-dev --body "<your-github-id>"
gh secret set GIT_PLATFORM_REPO_NAME --env k8s-dev --body "<your-githhub-repository-name>"

gh secret set K8S_CLUSTER_NAME --env k8s-dev --body "istory"
gh secret set K8S_NAMESPACE --env k8s-dev --body "istory-dev"

gh secret set AWS_ACCESS_KEY_ID --env k8s-dev --body "<your-aws-access-key-id>"
gh secret set AWS_SECRET_ACCESS_KEY --env k8s-dev --body "<your-aws-access-key>"
gh secret set AWS_REGION --env k8s-dev --body "<your-aws-region>"
  
  • ํŒŒ์ผ ๊ถŒํ•œ ๋ถ€์—ฌ ๋ฐ ์‹คํ–‰
  chmod +x .github/workflows/create-secret.sh

.github/workflows/create-secret.sh
  

15. Workflow ์ƒ์„ฑ

- MySQL ์„œ๋น„์Šค ๋ฐ ํ™˜๊ฒฝ์„ค์ •

ํŒŒ์ผ ์œ„์น˜ : .github/workflows/istory-aws-eks-dev.yml

  #8
name: Istory Deploy to AWS EKS DEV
on:
  push:
    branches: ['main', 'test']
permissions:
  contents: read
  actions: read
  packages: write
jobs:
  build:
    if: contains(github.event.head_commit.message, '[deploy-dev]') # ํŠน์ • ํƒœ๊ทธ์—๋งŒ ์‹คํ–‰
    runs-on: ubuntu-latest
    environment: k8s-dev # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋ฐ ์‹œํฌ๋ฆฟ ์ €์žฅ๊ณต๊ฐ„
    env:
      DOCKER_IMAGE: ${{ secrets.DOCKER_USERNAME }}/istory
      DOCKER_TAG: ${{ github.run_number }}
    services:
      mysql:
        image: mysql:8.0
        env:
          # root ๊ณ„์ • ๋น„๋ฐ€๋ฒˆํ˜ธ
          MYSQL_ROOT_PASSWORD: ${{ secrets.MYSQL_ROOT_PASSWORD }} 
          # ์‚ฌ์šฉ์ž ๊ณ„์ •
          MYSQL_USER: ${{ secrets.MYSQL_USER }} # user
          # ์‚ฌ์šฉ์ž ๊ณ„์ • ๋น„๋ฐ€๋ฒˆํ˜ธ
          MYSQL_PASSWORD: ${{ secrets.MYSQL_PASSWORD }}
          # ์‚ฌ์šฉ์ž ๊ณ„์ • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค
          MYSQL_DATABASE: ${{ secrets.MYSQL_DATABASE }} # istory
        ports:
          - 3306:3306
        options: >-
          --health-cmd="mysqladmin ping"
          --health-interval=10s
          --health-timeout=5s
          --health-retries=3
    steps:
      - name: AWS CLI ActionSet ์„ค์ •
        uses: aws-actions/configure-aws-credentials@v3
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: kubectl ์„ค์น˜
        run: |
          curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
          chmod +x kubectl
          sudo mv kubectl /usr/local/bin/

      - name: kubeconfig ์—…๋ฐ์ดํŠธ
        run: |
          aws eks update-kubeconfig --region ${{ secrets.AWS_REGION }} --name ${{ secrets.K8S_CLUSTER_NAME }}

      - name: kustomize ์„ค์น˜
        run: |
          curl -s https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh | bash
          sudo mv kustomize /usr/local/bin

      - name: JDK 17 ์„ค์น˜
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'
  

- ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋นŒ๋“œ

ํŒŒ์ผ ์œ„์น˜ : .github/workflows/istory-aws-eks-dev.yml

        - name: ์†Œ์Šค์ฝ”๋“œ ๋‹ค์šด๋กœ๋“œ
        uses: actions/checkout@v4 
        with:
          ref: ${{ github.ref }}
          path: .
  
      - name: ๊ฐœ๋ฐœ์šฉ application.yml ์ƒ์„ฑ
        run: |
          cat > src/main/resources/application.yml << EOF
          spring:
            datasource:
              # url: ${{ secrets.DATABASE_URL }} # ์˜ˆdbc:mysql://localhost:3306/istory
              url: jdbc:mysql://localhost:3306/istory
              username: ${{ secrets.MYSQL_USER }}
              password: ${{ secrets.MYSQL_PASSWORD }}
              driver-class-name: com.mysql.cj.jdbc.Driver
            jpa:
              database-platform: org.hibernate.dialect.MySQL8Dialect
              hibernate:
                ddl-auto: update
              show-sql: true
            application:
              name: USER-SERVICE
            jwt:
              issuer: user@gmail.com
              secret_key: study-springboot
          management:
            endpoints:
              web:
                exposure:
                  include: health,info
            endpoint:
              health:
                show-details: always
          EOF

      - name: Gradle ์„ค์ •
        uses: gradle/gradle-build-action@v2
        
      - name: JAVA build with TEST
        run: ./gradlew build

      - name: Docker ๋””๋ ‰ํ† ๋ฆฌ๋กœ JAR ํŒŒ์ผ ๋ณต์‚ฌ
        run: |
          mkdir -p xinfra/docker/build/libs/
          cp build/libs/*.jar xinfra/docker/
          ls xinfra/docker/
  

- ์ปจํ…Œ์ด๋„ˆ ๋นŒ๋“œ ๋ฐ ์—…๋กœ๋“œ

ํŒŒ์ผ ์œ„์น˜ : .github/workflows/istory-aws-eks-dev.yml

        - name: ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ๋นŒ๋“œ
        run: | 
          docker build ./xinfra/docker -t ${{ secrets.DOCKER_USERNAME }}/istory:${{ env.DOCKER_TAG }} -f ./xinfra/docker/Dockerfile
          docker tag ${{ secrets.DOCKER_USERNAME }}/istory:${{ env.DOCKER_TAG }} ${{ secrets.DOCKER_USERNAME }}/istory:latest

      - name: Docker Hub ๋กœ๊ทธ์ธ
        uses: docker/login-action@v3.0.0
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}
          logout: true

      - name: Docker Hub ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ
        run: |
          docker push ${{ secrets.DOCKER_USERNAME }}/istory:${{ env.DOCKER_TAG }}
          docker push ${{ secrets.DOCKER_USERNAME }}/istory:latest
  
  • 2.4 ์ด๋ฏธ์ง€ ํƒœ๊ทธ ๋ณ€๊ฒฝ
    ํŒŒ์ผ ์œ„์น˜ : .github/workflows/istory-aws-eks-dev.yml
        - name: ์„œ๋น„์Šค ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์ฒดํฌ์•„์›ƒ
        uses: actions/checkout@v4
        with:
          repository: ${{ secrets.GIT_USERNAME }}/${{ secrets.GIT_PLATFORM_REPO_NAME }}
          ref: ${{ github.ref }} # ๋ฐ”๊พธ๊ธฐ
          path: .
          token: ${{ secrets.GIT_ACCESS_TOKEN }}
  
      - name: ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค secret ์ƒ์„ฑ (istory-db-secret)
        run: |
          kubectl create secret generic istory-db-secret \
            --from-literal=MYSQL_USER=${{ secrets.MYSQL_USER }} \
            --from-literal=MYSQL_PASSWORD=${{ secrets.MYSQL_PASSWORD }} \
            --from-literal=DATABASE_URL=${{ secrets.DATABASE_URL }} \
            --from-literal=MYSQL_ROOT_PASSWORD=${{ secrets.MYSQL_ROOT_PASSWORD }} \
            --namespace=${{ secrets.K8S_NAMESPACE}} \
            --dry-run=client -o yaml | kubectl apply -f -

      - name: ์ด๋ฏธ์ง€ ํƒœ๊ทธ ์—…๋ฐ์ดํŠธ (kustomize)
        run: |
          cd overlay/aws-dev
          kustomize edit set image ${{ secrets.DOCKER_USERNAME }}/istory=${{ secrets.DOCKER_USERNAME }}/istory:${{ env.DOCKER_TAG }}
      - name: ์„œ๋น„์Šค ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์ตœ์ข… ์—…๋ฐ์ดํŠธ
        run: |
          git config --global user.name 'github-actions[bot]'
          git config --global user.email 'github-actions[bot]@users.noreply.github.com'
          git commit -am "Update image tag to ${{ env.DOCKER_TAG }}"
          git push origin ${{ github.ref_name }} 
  

- ์ „์ฒดํŒŒ์ผ

  #8
name: Istory Deploy to AWS EKS DEV
on:
  push:
    branches: [ 'main', 'test' ]
permissions:
  contents: read
  actions: read
  packages: write
jobs:
  build:
    if: contains(github.event.head_commit.message, '[deploy-dev]') # ํŠน์ • ํƒœ๊ทธ์—๋งŒ ์‹คํ–‰
    runs-on: ubuntu-latest
    environment: k8s-dev # ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๋ฐ ์‹œํฌ๋ฆฟ ์ €์žฅ๊ณต๊ฐ„
    env:
      DOCKER_IMAGE: ${{ secrets.DOCKER_USERNAME }}/istory
      DOCKER_TAG: ${{ github.run_number }}
    services:
      mysql:
        image: mysql:8.0
        env:
          # root ๊ณ„์ • ๋น„๋ฐ€๋ฒˆํ˜ธ
          MYSQL_ROOT_PASSWORD: ${{ secrets.MYSQL_ROOT_PASSWORD }} 
          # ์‚ฌ์šฉ์ž ๊ณ„์ •
          MYSQL_USER: ${{ secrets.MYSQL_USER }} # user
          # ์‚ฌ์šฉ์ž ๊ณ„์ • ๋น„๋ฐ€๋ฒˆํ˜ธ
          MYSQL_PASSWORD: ${{ secrets.MYSQL_PASSWORD }}
          # ์‚ฌ์šฉ์ž ๊ณ„์ • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค
          MYSQL_DATABASE: ${{ secrets.MYSQL_DATABASE }} # istory
        ports:
          - 3306:3306
        options: >-
          --health-cmd="mysqladmin ping"
          --health-interval=10s
          --health-timeout=5s
          --health-retries=3
    steps:
      - name: AWS CLI ActionSet ์„ค์ •
        uses: aws-actions/configure-aws-credentials@v3
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: kubectl ์„ค์น˜
        run: |
          curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
          chmod +x kubectl
          sudo mv kubectl /usr/local/bin/

      - name: kubeconfig ์—…๋ฐ์ดํŠธ
        run: |
          aws eks update-kubeconfig --region ${{ secrets.AWS_REGION }} --name ${{ secrets.K8S_CLUSTER_NAME }}

      - name: kustomize ์„ค์น˜
        run: |
          curl -s https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh | bash
          sudo mv kustomize /usr/local/bin

      - name: JDK 17 ์„ค์น˜
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: ์†Œ์Šค์ฝ”๋“œ ๋‹ค์šด๋กœ๋“œ
        uses: actions/checkout@v4 
        with:
          ref: ${{ github.ref }}
          path: .
  
      - name: ๊ฐœ๋ฐœ์šฉ application.yml ์ƒ์„ฑ
        run: |
          cat > src/main/resources/application.yml << EOF
          spring:
            datasource:
              # url: ${{ secrets.DATABASE_URL }} # ์˜ˆdbc:mysql://localhost:3306/istory
              url: jdbc:mysql://localhost:3306/istory
              username: ${{ secrets.MYSQL_USER }}
              password: ${{ secrets.MYSQL_PASSWORD }}
              driver-class-name: com.mysql.cj.jdbc.Driver
            jpa:
              database-platform: org.hibernate.dialect.MySQL8Dialect
              hibernate:
                ddl-auto: update
              show-sql: true
            application:
              name: USER-SERVICE
            jwt:
              issuer: user@gmail.com
              secret_key: study-springboot
          management:
            endpoints:
              web:
                exposure:
                  include: health,info
            endpoint:
              health:
                show-details: always
          EOF

      - name: Gradle ์„ค์ •
        uses: gradle/gradle-build-action@v2
        
      - name: JAVA build with TEST
        run: ./gradlew build -x test

      - name: Docker ๋””๋ ‰ํ† ๋ฆฌ๋กœ JAR ํŒŒ์ผ ๋ณต์‚ฌ
        run: |
          mkdir -p xinfra/docker/build/libs/
          cp build/libs/*.jar xinfra/docker/
          ls xinfra/docker/
      - name: ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€ ๋นŒ๋“œ
        run: | 
          docker build ./xinfra/docker -t ${{ secrets.DOCKER_USERNAME }}/istory:${{ env.DOCKER_TAG }} -f ./xinfra/docker/Dockerfile
          docker tag ${{ secrets.DOCKER_USERNAME }}/istory:${{ env.DOCKER_TAG }} ${{ secrets.DOCKER_USERNAME }}/istory:latest

      - name: Docker Hub ๋กœ๊ทธ์ธ
        uses: docker/login-action@v3.0.0
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}
          logout: true

      - name: Docker Hub ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ
        run: |
          docker push ${{ secrets.DOCKER_USERNAME }}/istory:${{ env.DOCKER_TAG }}
          docker push ${{ secrets.DOCKER_USERNAME }}/istory:latest

      - name: ์„œ๋น„์Šค ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์ฒดํฌ์•„์›ƒ
        uses: actions/checkout@v4
        with:
          repository: ${{ secrets.GIT_USERNAME }}/${{ secrets.GIT_PLATFORM_REPO_NAME }}
          ref: ${{ github.ref }} # istory-web-k8s, istory-platform ์˜ ๋™์ผํ•œ ๋ธŒ๋ Œ์น˜ ๋ผ๋Š” ๊ฐ€์ •
          path: .
          token: ${{ secrets.GIT_ACCESS_TOKEN }}
  
      - name: ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค secret ์ƒ์„ฑ (istory-db-secret)
        run: |
          kubectl create secret generic istory-db-secret \
            --from-literal=MYSQL_USER=${{ secrets.MYSQL_USER }} \
            --from-literal=MYSQL_PASSWORD=${{ secrets.MYSQL_PASSWORD }} \
            --from-literal=DATABASE_URL=${{ secrets.DATABASE_URL }} \
            --from-literal=MYSQL_ROOT_PASSWORD=${{ secrets.MYSQL_ROOT_PASSWORD }} \
            --namespace=${{ secrets.K8S_NAMESPACE}} \
            --dry-run=client -o yaml | kubectl apply -f -

      - name: ์ด๋ฏธ์ง€ ํƒœ๊ทธ ์—…๋ฐ์ดํŠธ (kustomize)
        run: |
          ls
          cd awsk-eks/overlay/aws-dev
          kustomize edit set image ${{ secrets.DOCKER_USERNAME }}/istory=${{ secrets.DOCKER_USERNAME }}/istory:${{ env.DOCKER_TAG }}

      - name: ์„œ๋น„์Šค ๋ฆฌํฌ์ง€ํ† ๋ฆฌ ์ตœ์ข… ์—…๋ฐ์ดํŠธ
        run: |
          git config --global user.name 'github-actions[bot]'
          git config --global user.email 'github-actions[bot]@users.noreply.github.com'
          git commit -am "Update image tag to ${{ env.DOCKER_TAG }}"
          git push origin ${{ github.ref_name }} 
  

16. ArgoCD ํ™•์ธ ๋ฐ ์›น์‚ฌ์ดํŠธ ์ ‘์†

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ˆ˜์ •ํ•œ๊ฒƒ์„ ์ปค๋ฐ‹ํ•˜๊ณ  ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ์—…๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค.

- Commit ๋ฐ Push

  git add .
git commit -am "[aws-dev deploy]add workflow"
git push origin main
  

- ArgoCD URL ์กฐํšŒ ๋ฐ ์ ‘์†

URL ์ ‘์†ํ•ด์„œ Commit Hash ๊ฐ’์„ ๋น„๊ตํ•ด์„œ ๋‹ฌ๋ผ ์ง€๋Š”์ง€ ํ™•์ธ ํ›„ Sync ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ๋™๊ธฐํ™” ํ•ฉ๋‹ˆ๋‹ค.

  kubectl get svc argocd-server -n argocd
  

- Istory URL ์กฐํšŒ ๋ฐ ์ ‘์†

Istory ์„œ๋น„์Šค์— ์ ‘์†ํ•ด์„œ ๋กœ๊ทธ์ธ ํ™”๋ฉด์˜ ๋ฒ„์ „์ด ๋งž๋Š”์ง€ ํ™•์ธ ํ•ฉ๋‹ˆ๋‹ค.

  kubectl get svc -n istory-dev 
  

http://<site-url> ๋กœ ์ ‘์†

[์—ฐ์Šต๋ฌธ์ œ] 9-1. aws-prod overlay ์ƒ์„ฑ

  • istory-prod ๋ผ๋Š” ๋ณ„๋„์˜ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
  • ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค๋Š” AWS RDS๋ฅผ ์‚ฌ์šฉ ํ•˜๋„๋ก ํ…Œ๋ผํผ ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ ํ•ฉ๋‹ˆ๋‹ค.

  • overlay/aws-prod ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ kustomzie ์— ์ถ”๊ฐ€ ํ•ฉ๋‹ˆ๋‹ค.
  • .env.secret ํŒŒ์ผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • kustomiztion.yml ์— DB ๋ถ€๋ถ„์„ ์‚ญ์ œ ํ•ฉ๋‹ˆ๋‹ค.(RDS ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์—)
  • patch-app-config.yml ํŒŒ์ด์„ ๋งŒ๋“ค์–ด์„œ RDS URL ๋กœ ๋ณ€๊ฒฝ ํ•ฉ๋‹ˆ๋‹ค.
  • patch-deploy.yml ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์„œ annotation(istory.io/env: prod) ๊ณผ replicas ๊ฐœ์ˆ˜ ๋ณ€๊ฒฝ ํ•ฉ๋‹ˆ๋‹ค.
  • patch-lb-annotations.yml ์˜ annotation(istory.io/env: prod)๋กœ ๋ณ€๊ฒฝ
  • ๋ณ€๊ฒฝ๋œ ์ฝ”๋“œ๋ฅผ istory-platform-k8s ์— commit ํ›„ push ํ•ฉ๋‹ˆ๋‹ค.
  • ArgoCD ์—์„œ Repository ์ƒ์„ฑ ๋ฐ Application ์„ค์ • ํ•ฉ๋‹ˆ๋‹ค.

[์—ฐ์Šต๋ฌธ์ œ] 9-2. ConfigMapGenerator ์‚ฌ์šฉ

ํ˜„์žฌ istory-app-config.yml ํŒŒ์ผ์„ ConfigMapGenerator ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜์„ธ์š”
์ฐธ์กฐ ์‚ฌ์ดํŠธ : https://env.simplestep.ca/