Docker - Jenkins, Gitlab

K8S - argocd

springboot

maven

Dockerdescktop - kubernetes

Spring 프로젝트 생성

https://start.spring.io

image-20251016212532231

image-20251016212519402

image-20251016212659209

git init
git commit -m 'init'

Docker 내 gitlab 설치

docker-compose.yml 파일 사용

services:
  gitlab:
    image: gitlab/gitlab-ce:latest
    container_name: gitlab
    hostname: gitlab
    restart: always
    ports:
      - "8929:8929"   # Web UI
      - "2224:22"     # SSH for git clone
    environment:
      TZ: Asia/Seoul
      GITLAB_OMNIBUS_CONFIG: |
        external_url 'http://localhost:8929'
    volumes:
      - ./config:/etc/gitlab
      - ./logs:/var/log/gitlab
      - ./data:/var/opt/gitlab
    extra_hosts:
      - "jenkins.local:host-gateway"
    networks:
      - cicd-net

networks:
  cicd-net:
    external: true


**networks는 jenkins와 gitlab 동일 네트워크로..**

docker gitlab 설치

docker compose up -d

image-20251016212921965

Gitlab 초기 관리 계정 : root

gitlab 초기 관리 비번 : /etc/gitlab 혹은 로컬 볼륨 .config에서 확인

image-20251016212907091

http://localhost:8929 로 접속 가능.

root / O6Lexg1M4u6G/LWsDIdfOBpl1gxJ+fA1WPy2fMx1140=

image-20251016213056737

가입정책 변경 - 체크박스 해제

Sign-up enabled

image-20251016213357461

계정명 변경

image-20251016213421782

비밀번호 변경

image-20251016213449955

재로그인

image-20251016213509187

프로젝트 생성

image-20251016213530797

공백 프로젝트 생성

image-20251016213542503

image-20251016213555753

로컬 pc ssh key 생성 : ssh-keygen 이용

계정에 로컬 pc SSH 키 등록

image-20251016213635169

로컬 .ssh 에서 사용할 pub 키를 gitlab에 등록.

cat ~/.ssh/{name}.pub

image-20251016213831938

연결 테스트(localPC에서 Docker Gitlab으로) :

ssh git@localhost -p 2224

알고리즘 기본 이름이 아닌, 다른 이름으로 지정했을 경우,

  • ssh git@localhost -p 2224 -i /root/.ssh/id_jenkins
    

image-20251016214023918

Spring 프로젝트와 연결

image-20251016214337555

git remote add origin ssh://git@localhost:2224/devsungyeon/k8sdemo.git

image-20251016214702819

git pull 시, 충돌 발생하면,

강제로 병합 허용 : git pull origin main –allow-unrelated-histories

git push

image-20251016214548022

push 확인

image-20251016214605805

Docker 내 Jenkins 설치

image-20251016214727060

Dockerfile

Dockerfile 사용 이유는 기본 Jenkins 이미지에는 docker CLI가 없음.

따라서 해당 이미지에 docker 설치후, 다시 빌드하여 사용.

# Dockerfile
FROM jenkins/jenkins:lts-jdk17

USER root

# Docker CLI 설치
RUN apt-get update && \
    apt-get install -y docker.io && \
    apt-get clean

# docker 그룹 접근 허용 (root는 이미 가능하지만 안전하게)
RUN usermod -aG docker root

# Jenkins home 유지
VOLUME /var/jenkins_home

EXPOSE 8080 50000

docker-compose.yml 파일 사용

services:
  jenkins:
    build: . # Dockerfile 사용?
    container_name: jenkins
    restart: always
    user: root
    ports:
      - "9090:8080"   # ← 외부 접속 포트 변경
      - "50000:50000"
    environment:
      - TZ=Asia/Seoul
    volumes:
      - ./jenkins_home:/var/jenkins_home
      - ./jenkins_ssh:/root/.ssh        # ✅ SSH 키 영구 저장
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - cicd-net

networks:
  cicd-net:
    external: true

Dockerfile build

docker compose build

image-20251016214754603

docker compose up

docker compose up -d

image-20251016214817653

http://localhost:9090 로 접속 가능.

초기 비번 : ./jenkins_home/secrets/initialAdminPassword

image-20251016214838496

image-20251016214850492

필수플러그인 설치

image-20251016214900503

계정 생성

image-20251016215621580

Jenkins 내 root 계정 ssh 키 생성

docker exec -it jenkins bash
ssh-keygen -t ed25519 -C "jenkins@gitlab" -f ~/.ssh/id_jenkins -N ""

in jenkins cert, we cant use passphase for ssh key. with passphase , there were error for connecting.

image-20251016215706154

id_jenkins.pub Gitlab계정의 ssh 키에 등록

cat ~/.ssh/id_jenkins.pub

image-20251016215732395

image-20251016215757358

ssh 접근 테스트 - 여기서 접근 가능해야, jenkins 웹에서도 접근 가능.

ssh -T git@host.docker.internal -p 2224 -i ~/.ssh/id_jenkins

image-20251016215828777

test project 생성

image-20251016215849411

image-20251016215942837

image-20251016220008519

Credentials 생성

cat ~/.ssh/id_jenkins

image-20251016220108123

image-20251016220123278

Credentials 선택후, 에러 사라짐

image-20251016220133347

브랜치명 수정

image-20251016220158223

빌드 테스트

image-20251016220230336

image-20251016220241231

Gitlab webhook 연결 with jenkins

Plugin Gitlab 설치 in Jenkins

image-20251016220415717

GitLab 계정에서 Access tokens 생성

image-20251016220610236

image-20251016221458892

image-20251016221520405

GitLab 연결 : Jenkins관리 - System - GitLab

image-20251016221706766

image-20251016221129664

image-20251016221645531

Jenkins Item 생성 (k8sdemo build) : Pipeline

image-20251016220344641

image-20251016221822831

Jenkins - Trigger 체크

image-20251016221813929

image-20251016221832732

Gitlab - 하기 중간 체크 필요 Allow requests to the local network from webhooks and integrations

image-20251016210603072

Jenkins에서 계정의 security 내 api token 발급

image-20251016210935275

image-20251016221938623

Gitlab - 웹훅 추가 시 , http://{user}:{jenkins_api_token}@jenkins.local:9090/project/k8sdemo_build

image-20251016222116580

웹훅 테스트

image-20251016222139758

image-20251016222156308

Jenkins 빌드 확인

image-20251016222309923

image-20251016222315837

Jenkins pipe라인 Definition 수정

image-20251016222950333

Spring에서 .gitlab-ci.yml, Dockerfile 및 Jenkinsfile 추가

.gitlab-ci.yml 추가 - gitlab은 repo만 수행하므로 아무작업 없음. runner 미추가

echo "# GitLab CI disabled — Jenkins handles CI/CD.
stages:
  - noop

disable_job:
  stage: noop
  script:
    - echo \"GitLab CI is disabled. Jenkins handles all builds.\"
  rules:
    - when: never" > .gitlab-ci.yml

git add .gitlab-ci.yml
git commit -m "disable GitLab CI completely, use Jenkins only"
git push

Dockerfile

# Dockerfile
FROM openjdk:17-jdk-slim

WORKDIR /app

# Maven으로 빌드된 JAR 파일 복사
COPY target/*.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java","-jar","/app/app.jar"]

Jenkinsfile

pipeline {
  agent any
  environment {
    IMAGE_NAME = 'k8sdemo'
  }
  stages {
    stage('Checkout') {
      steps {
        checkout scm
      }
    }
    stage('Maven Build') {
      steps {
        echo '🔧 Building Spring Boot application...'
        sh './mvnw -B clean package -DskipTests'
      }
    }
    stage('Docker Build') {
      steps {
        script {
          def GIT_COMMIT_HASH = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
          echo "🐳 Building Docker image: ${IMAGE_NAME}:${GIT_COMMIT_HASH}"
          sh "docker build -t ${IMAGE_NAME}:${GIT_COMMIT_HASH} ."
        }
      }
    }
  }
  post {
    success {
      echo '✅ Build successful!'
    }
    failure {
      echo '❌ Build failed.'
    }
  }
}
	

image-20251016222403395

로컬에서 추가후 push 후 자동 build 테스트 확인

image-20251016222435295

image-20251016223035613

image-20251016223104973

docker images | grep k8sdemo

image-20251016224742557

K8s-configs repo 생성

✅ 1️⃣ ArgoCD가 인식할 GitOps Repo 준비

ArgoCD는 Git 리포지토리의 YAML 정의를 감시합니다. 즉, Kubernetes 매니페스트가 담긴 별도의 Git repo (예: k8s-configs) 가 필요합니다.

예시 구조:

k8s-configs/
 ├── apps/
 │    └── k8sdemo/
 │         ├── deployment.yaml
 │         ├── service.yaml
 │         └── kustomization.yaml
 └── README.md

Gitlab 공백 프로젝트 생성

로컬로 clone

파일들 추가 apps/*

push to Gitlab from local


✅ 2️⃣ deployment.yaml 예시

apiVersion: apps/v1
kind: Deployment
metadata:
  name: k8sdemo
  labels:
    app: k8sdemo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: k8sdemo
  template:
    metadata:
      labels:
        app: k8sdemo
    spec:
      containers:
        - name: k8sdemo
          image: k8sdemo:latest   # ✅ Jenkins가 빌드 후 이 부분을 자동 업데이트
          ports:
            - containerPort: 8080

ArgoCD는 이 image 값을 기준으로 배포 대상을 인식합니다.

Jenkinsfile 수정

pipeline {
  agent any
  environment {
    IMAGE_NAME = 'k8sdemo'
    GITOPS_REPO = 'git@host.docker.internal:devsungyeon/k8s-configs.git'
  }

  stages {
    stage('Checkout') {
      steps { checkout scm }
    }

    stage('Who Am I') {
      steps {
        sh 'whoami'
        sh 'ls -al ~'
        sh 'ls -al ~/.ssh || echo "⚠️ No .ssh folder found"'
      }
    }

    stage('Maven Build') {
      steps {
        echo '🔧 Building Spring Boot application...'
        sh './mvnw -B clean package -DskipTests'
      }
    }

    stage('Docker Build') {
      steps {
        script {
          def GIT_COMMIT_HASH = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
          env.GIT_COMMIT_HASH = GIT_COMMIT_HASH   // 🔹 후속 단계에서 접근 가능하도록 환경변수 등록
          def IMAGE_TAG = "${IMAGE_NAME}:${GIT_COMMIT_HASH}"
          sh "docker build -t ${IMAGE_TAG} ."
          sh "docker tag ${IMAGE_TAG} ${IMAGE_NAME}:latest"
        }
      }
    }

    stage('Update GitOps Repo') {
      steps {
        script {
          sh """
            echo "🔑 Registering SSH host..."
            ssh-keyscan -p 2224 host.docker.internal >> ~/.ssh/known_hosts || true

            echo "🧩 Cloning GitOps repository..."
            rm -rf k8s-configs
            bash -c "GIT_SSH_COMMAND='ssh -i ~/.ssh/id_jenkins -p 2224' git clone ${env.GITOPS_REPO}"

            cd k8s-configs/apps/k8sdemo
            echo "📝 Updating deployment.yaml with image tag ${env.GIT_COMMIT_HASH}"
            sed -i 's|image:.*|image: k8sdemo:${env.GIT_COMMIT_HASH}|' deployment.yaml

            git config --global user.email "jenkins@local"
            git config --global user.name "Jenkins CI"
            git add .
            git commit -m "Update image tag to ${env.GIT_COMMIT_HASH}" || echo "No changes to commit"

            echo "🚀 Pushing updates..."
            bash -c "GIT_SSH_COMMAND='ssh -i ~/.ssh/id_jenkins -p 2224' git push origin main"
          """
        }
      }
    }
 }

  post {
    success { echo '✅ Build and update successful!' }
    failure { echo '❌ Build failed.' }
  }
}

push 하여 테스트

image-20251016232406970

Docker image 최신 몇개만 남기고 지우기

image-20251017165038836

pipeline {
  agent any
  environment {
    IMAGE_NAME = 'k8sdemo'
    GITOPS_REPO = 'git@host.docker.internal:devsungyeon/k8s-configs.git'
  }

  stages {
    stage('Checkout') {
      steps { checkout scm }
    }

    stage('Who Am I') {
      steps {
        sh 'whoami'
        sh 'ls -al ~'
        sh 'ls -al ~/.ssh || echo "⚠️ No .ssh folder found"'
      }
    }

    stage('Maven Build') {
      steps {
        echo '🔧 Building Spring Boot application...'
        sh './mvnw -B clean package -DskipTests'
      }
    }

    stage('Docker Build') {
      steps {
        script {
          def GIT_COMMIT_HASH = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
          env.GIT_COMMIT_HASH = GIT_COMMIT_HASH   // 🔹 후속 단계에서 접근 가능하도록 환경변수 등록
          def IMAGE_TAG = "${IMAGE_NAME}:${GIT_COMMIT_HASH}"
          sh "docker build -t ${IMAGE_TAG} ."
          sh "docker tag ${IMAGE_TAG} ${IMAGE_NAME}:latest"
        }
      }
    }

    stage('Update GitOps Repo') {
      steps {
        script {
          sh """
            echo "🔑 Registering SSH host..."
            ssh-keyscan -p 2224 host.docker.internal >> ~/.ssh/known_hosts || true

            echo "🧩 Cloning GitOps repository..."
            rm -rf k8s-configs
            bash -c "GIT_SSH_COMMAND='ssh -i ~/.ssh/id_jenkins -p 2224' git clone ${env.GITOPS_REPO}"

            cd k8s-configs/apps/k8sdemo
            echo "📝 Updating deployment.yaml with image tag ${env.GIT_COMMIT_HASH}"
            sed -i 's|image:.*|image: k8sdemo:${env.GIT_COMMIT_HASH}|' deployment.yaml

            git config --global user.email "jenkins@local"
            git config --global user.name "Jenkins CI"
            git add .
            git commit -m "Update image tag to ${env.GIT_COMMIT_HASH}" || echo "No changes to commit"

            echo "🚀 Pushing updates..."
            bash -c "GIT_SSH_COMMAND='ssh -i ~/.ssh/id_jenkins -p 2224' git push origin main"
          """
        }
      }
    }
  }

  post {
    success { 
      // 수정 부분
      echo '✅ Build and update successful!' 
      echo '✅ Build and update successful!'
      sh '''
        echo "🧹 Cleaning up old Docker images..."
        # 최근 3개의 k8sdemo 이미지만 남기고 나머지는 삭제
        docker images k8sdemo --format "" | tail -n +4 | xargs -r docker rmi -f || true
        docker image prune -f
      '''
    }
    failure { echo '❌ Build failed.' }
  }
}

image-20251017165548990

Argocd 설치

✅ 1️⃣ ArgoCD 설치 (Kubernetes 환경에 설치)

🔹 ① 네임스페이스 생성

kubectl create namespace argocd

🔹 ② 공식 매니페스트로 설치

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

🔹 ③ 설치 확인

kubectl get pods -n argocd

argocd-server, argocd-repo-server, argocd-dex-server 등이 Running 상태가 될 때까지 기다립니다 (1~2분 정도).

image-20251017170012251

✅ 2️⃣ ArgoCD 웹 접속 설정

🔹 ① 서비스 확인

kubectl get svc -n argocd

보통 이렇게 나옵니다:

NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)             AGE
argocd-server           ClusterIP   10.101.120.41    <none>        80/TCP,443/TCP      2m
argocd-repo-server      ClusterIP   10.101.218.90    <none>        8081/TCP,8084/TCP   2m
...

🔹 ② 포트포워딩으로 로컬 접속

kubectl port-forward svc/argocd-server -n argocd 8080:443

➡ 브라우저에서 접속: 👉 https://localhost:8080


✅ 3️⃣ 로그인 정보 확인

초기 사용자:

Username: admin

비밀번호:

kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo

이제 UI에서 로그인 가능합니다 🎯


✅ 4️⃣ 자동 로그인 (선택)

CLI에서 로그인할 수도 있어요:

argocd login localhost:8080 \
  --username admin \
  --password $(kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d) \
  --insecure
argocd login localhost:8080 --username admin --password <혹은 변경비밀번호> --insecure

✅ 5️⃣ ArgoCD 설치 확인

argocd version
argocd app list

→ 버전과 서버 연결이 정상적으로 출력되면 성공입니다.


ArgoCD에 k8sdemo 애플리케이션 등록 → 자동 배포 연결


✅ 1️⃣ GitOps Repo 구조 확인

지금 k8s-configs 리포지토리에 deployment.yaml만 있죠. ArgoCD는 하나의 앱 단위로 deployment + service + kustomization 구성이 필요합니다.

📁 폴더 구조를 이렇게 만들어주세요 👇

k8s-configs/
└── apps/
    └── k8sdemo/
        ├── deployment.yaml
        ├── service.yaml
        └── kustomization.yaml

✅ 2️⃣ service.yaml 생성

apiVersion: v1
kind: Service
metadata:
  name: k8sdemo
  labels:
    app: k8sdemo
spec:
  type: NodePort
  selector:
    app: k8sdemo
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8080
      nodePort: 30080

✅ 3️⃣ kustomization.yaml 생성

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - service.yaml

ArgoCD는 kustomization.yaml을 기준으로 해당 폴더를 “앱 단위”로 인식합니다.


✅ 4️⃣ GitLab에 커밋 & 푸시

로컬에서 아래처럼 커밋해 주세요 👇

git add apps/k8sdemo/service.yaml apps/k8sdemo/kustomization.yaml
git commit -m "Add service and kustomization for ArgoCD"
git push

Argocd repo add

argocd repo add http://host.docker.internal:8929/devsungyeon/k8s-configs.git
–username devsungyeon
–password glpat-chuT4RQ_Yv-rzTPADG4JrG86MQp1OjEH.01.0w0yjr3g6
–insecure-skip-server-verification

password는 personal access token

✅ 5️⃣ ArgoCD 앱 등록 (CLI 방식)

K8s-configs repo 디렉토리에서 수행

argocd app create k8sdemo \
  --repo http://host.docker.internal:8929/devsungyeon/k8s-configs.git \
  --path apps/k8sdemo \
  --dest-server https://kubernetes.default.svc \
  --dest-namespace default \
  --sync-policy automated

🔹 --sync-policy automated: Git 변경 시 자동 배포 🔹 --path apps/k8sdemo: 우리가 만든 폴더 경로


✅ 6️⃣ 상태 확인

argocd app list
argocd app get k8sdemo

STATUS: Synced / HEALTH: Healthy 가 나오면 Kubernetes에 배포가 완료된 상태입니다.


✅ 7️⃣ 배포 확인

kubectl get pods
kubectl get svc

k8sdemo Deployment 및 Service가 실제로 생성되어 있으면 성공 🎯

image-20251017230452105

지금 kubectl get all 결과를 보면:

service/k8sdemo  NodePort  80:30995/TCP

즉, 외부 접근 포트가 30995로 자동 할당된 상태예요.


✅ 바로 접근 방법

🖥 Docker Desktop Kubernetes 사용 중이라면:

로컬 브라우저에서 아래 주소 입력 👇

http://localhost:30995

이게 바로 k8sdemo의 Spring Boot 서버 주소입니다.

최종 단계

/hello push해서 반영 테스트 해보기

✅ 1️⃣ Controller 추가

src/main/java/.../controller/HelloController.java 파일을 새로 만드세요.

package com.example.k8sdemo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "Hello from k8sdemo!";
    }
}

⚙️ 2️⃣ 로컬에서 먼저 테스트

Spring Boot 로컬 실행 포트 변경

application.properties 또는 application.yml에 포트를 임시로 바꾸세요.

📄 src/main/resources/application.properties

server.port=8085

그 후 실행:

./mvnw spring-boot:run

접속:

http://localhost:8085/hello

그리고 push 하여 테스트.

image-20251017232802674

접속:

http://localhost:30995/hello

image-20251017232824703

아니면, 기존 argocd 포트를 다른걸로 변경해도 됨

image-20251017232936167

image-20251017232955547

🐳 Kubernetes에 PostgreSQL 추가하기 (with Spring Boot)

/hello 배포 후 Postgres DB를 추가하고, Spring Boot에서 연결 테스트하는 단계


✅ 1️⃣ kustomization.yaml 수정

postgres 관련 리소스를 함께 관리하도록 추가

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - service.yaml
  - postgres-deployment.yaml
  - postgres-service.yaml

✅ 2️⃣ postgres-deployment.yaml 추가

PersistentVolumeClaim + Postgres Deployment 설정

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: postgres-pvc
  namespace: default
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: postgres
  namespace: default
spec:
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:15
          ports:
            - containerPort: 5432
          env:
            - name: POSTGRES_DB
              value: k8sdemo
            - name: POSTGRES_USER
              value: demo
            - name: POSTGRES_PASSWORD
              value: demo1234
          volumeMounts:
            - name: postgres-storage
              mountPath: /var/lib/postgresql/data
      volumes:
        - name: postgres-storage
          persistentVolumeClaim:
            claimName: postgres-pvc

✅ 3️⃣ postgres-service.yaml 추가

Spring Boot 애플리케이션이 내부 ClusterIP로 접근할 수 있도록 설정

apiVersion: v1
kind: Service
metadata:
  name: postgres-service
  namespace: default
spec:
  type: ClusterIP
  selector:
    app: postgres
  ports:
    - port: 5432
      targetPort: 5432

✅ 4️⃣ pom.xml 수정

PostgreSQL JDBC 드라이버 의존성 추가

<dependency>
  <groupId>org.postgresql</groupId>
  <artifactId>postgresql</artifactId>
  <version>42.7.2</version>
</dependency>

✅ 5️⃣ application.properties 수정

Spring Boot에서 Postgres 연결 설정

spring.datasource.url=jdbc:postgresql://postgres-service:5432/k8sdemo
spring.datasource.username=demo
spring.datasource.password=demo1234
spring.datasource.driver-class-name=org.postgresql.Driver

# JPA 설정 (선택)
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect

Db connection test

package com.example.k8sdemo.controller;

import com.example.k8sdemo.entity.TestEntity;
import com.example.k8sdemo.repository.TestRepository;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {
    private final TestRepository repo;

    public TestController(TestRepository repo) {
        this.repo = repo;
    }

    @GetMapping("/health/db")
    public String checkDb() {
        repo.save(new TestEntity("ok"));
        long count = repo.count();
        return "✅ DB Connected! (rows=" + count + ")";
    }
}

참고) Git clone

git clone (localPC에서 Docker Gitlab으로) :

git clone ssh://git@localhost:2224/devsungyeon/k8sdemo.git

알고리즘 기본 이름이 아닌, 다른 이름으로 지정했을 경우,

GIT_SSH_COMMAND='ssh -i ~/.ssh/id_jenkins -p 2224' git clone git@localhost:devsungyeon/k8sdemo.git

GIT_SSH_COMMAND=’ssh -i ~/.ssh/id_jenkins -p 2224’ git clone git@host.docker.internal:devsungyeon/k8sdemo.git

댓글남기기