test: k3s deploy action #10
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Spring Boot Multi-module K3s Deployment | |
on: | |
push: | |
branches: | |
- develop | |
env: | |
REGISTRY: "ghcr.io" | |
NAMESPACE: "depromeet" | |
IMAGE_NAME: "kasukabe-server" | |
MODULE: "layer-api" | |
jobs: | |
setup: | |
runs-on: ubuntu-latest | |
permissions: | |
contents: read | |
packages: write | |
outputs: | |
deploy_target: ${{ steps.set-env.outputs.DEPLOY_TARGET }} | |
sha_short: ${{ steps.sha_short.outputs.sha_short }} | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v2 | |
- name: Setup Env | |
id: set-env | |
run: | | |
if [[ "${GITHUB_REF}" == "refs/heads/main" ]]; then | |
echo "DEPLOY_TARGET=production" >> $GITHUB_OUTPUT | |
else | |
echo "DEPLOY_TARGET=development" >> $GITHUB_OUTPUT | |
fi | |
- name: Get short SHA | |
id: sha_short | |
run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT | |
build: | |
name: build | |
needs: [ setup ] | |
runs-on: ubuntu-latest | |
permissions: | |
contents: read | |
packages: write | |
env: | |
DEPLOY_TARGET: ${{ needs.setup.outputs.deploy_target }} | |
REGISTRY: "ghcr.io" | |
NAMESPACE: "depromeet" | |
IMAGE_NAME: "kasukabe-server" | |
# TODO: 멀티모듈 적용시 동적 할당 필요 | |
MODULE: "layer-api" | |
APPLICATION_SECRET_PROPERTIES: ${{ secrets.APPLICATION_SECRET_PROPERTIES }} | |
GOOGLE_CREDENTIALS: ${{ secrets.GOOGLE_CREDENTIALS }} | |
SHA_SHORT: ${{ needs.setup.outputs.sha_short }} | |
steps: | |
- name: Setup Java | |
uses: actions/setup-java@v4 | |
with: | |
java-version: '17' | |
distribution: 'corretto' | |
- name: Checkout sources | |
uses: actions/checkout@v4 | |
- name: Setup Gradle | |
uses: gradle/gradle-build-action@bd5760595778326ba7f1441bcf7e88b49de61a25 # v2.6.0 | |
- name: Create application-secret.properties | |
run: | | |
echo "${APPLICATION_SECRET_PROPERTIES}" > ./${{ env.MODULE }}/src/main/resources/application-secret.properties | |
- name: Build ${{ env.MODULE }} module | |
run: ./gradlew :${{ env.MODULE }}:build | |
- name: Run tests:${{ env.MODULE }} | |
run: ./gradlew :${{ env.MODULE }}:test | |
- name: login github container registry | |
uses: docker/login-action@v2 | |
with: | |
registry: ghcr.io | |
username: ${{ github.repository_owner }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Extract metadata (tags, labels) for Docker | |
id: meta | |
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 | |
with: | |
images: ${{ env.REGISTRY }}/${{ env.NAMESPACE }}/${{ env.IMAGE_NAME }}/${{ env.MODULE }} | |
- name: push | |
uses: docker/build-push-action@v4 | |
with: | |
context: ./${{ env.MODULE }} | |
platforms: linux/amd64 | |
push: true | |
tags: | | |
${{ env.REGISTRY }}/${{ env.NAMESPACE }}/${{ env.IMAGE_NAME }}:${{ env.SHA_SHORT }} | |
${{ env.REGISTRY }}/${{ env.NAMESPACE }}/${{ env.IMAGE_NAME }}:latest | |
deploy: | |
name: Deploy to K3s | |
needs: [ build, setup ] | |
runs-on: ubuntu-latest | |
env: | |
DEPLOY_TARGET: ${{ needs.setup.outputs.deploy_target }} | |
steps: | |
- name: Checkout sources | |
uses: actions/checkout@v4 | |
- name: Install kubectl | |
uses: azure/setup-kubectl@v1 | |
with: | |
version: 'v1.21.0' | |
- name: Set up kubeconfig | |
run: | | |
mkdir -p $HOME/.kube | |
echo "${{ secrets.KUBE_CONFIG }}" > $HOME/.kube/config | |
chmod 600 $HOME/.kube/config | |
- name: Create K3s deployment files | |
run: | | |
cat <<EOF > deployment.yaml | |
apiVersion: apps/v1 | |
kind: Deployment | |
metadata: | |
name: ${{ env.MODULE }}-deployment | |
namespace: default | |
spec: | |
replicas: 1 | |
selector: | |
matchLabels: | |
app: ${{ env.MODULE }} | |
template: | |
metadata: | |
labels: | |
app: ${{ env.MODULE }} | |
spec: | |
containers: | |
- name: ${{ env.MODULE }} | |
image: ${{ env.REGISTRY }}/${{ env.NAMESPACE }}/${{ env.IMAGE_NAME }}:${{ needs.setup.outputs.sha_short }} | |
ports: | |
- containerPort: 8080 | |
env: | |
- name: TZ | |
value: "Asia/Seoul" | |
- name: SPRING_PROFILES_ACTIVE | |
value: "${{ env.DEPLOY_TARGET }}" | |
volumeMounts: | |
- name: secret-volume | |
mountPath: /config/application-secret.properties | |
subPath: application-secret.properties | |
- name: log-volume | |
mountPath: /log | |
- name: tokens-volume | |
mountPath: /config/tokens | |
volumes: | |
- name: secret-volume | |
secret: | |
secretName: app-secret-dev | |
- name: log-volume | |
hostPath: | |
path: /${{ env.DEPLOY_TARGET }}/log/${{ env.MODULE }} | |
type: DirectoryOrCreate | |
- name: tokens-volume | |
emptyDir: {} | |
--- | |
apiVersion: v1 | |
kind: Service | |
metadata: | |
name: ${{ env.MODULE }}-service | |
namespace: default | |
spec: | |
selector: | |
app: ${{ env.MODULE }} | |
ports: | |
- protocol: TCP | |
port: 80 | |
targetPort: 8080 | |
--- | |
apiVersion: networking.k8s.io/v1 | |
kind: Ingress | |
metadata: | |
name: ${{ env.MODULE }}-ingress | |
namespace: default | |
annotations: | |
kubernetes.io/ingress.class: traefik | |
spec: | |
rules: | |
- host: stgapi.layerapp.io | |
http: | |
paths: | |
- path: / | |
pathType: Prefix | |
backend: | |
service: | |
name: ${{ env.MODULE }}-service | |
port: | |
number: 80 | |
EOF | |
- name: Deploy to K3s | |
run: | | |
kubectl apply -f deployment.yaml | |
- name: Verify deployment | |
run: | | |
# 최대 대기 시간 설정 | |
# 120 = 2분 | |
timeout=120 | |
elapsed=0 | |
interval=10 | |
while true; do | |
# 배포 상태 확인 | |
STATUS=$(kubectl rollout status deployment/${{ env.MODULE }}-deployment -n default --timeout=10s) | |
EXIT_CODE=$? | |
if [ $EXIT_CODE -eq 0 ]; then | |
echo "Deployment successful!" | |
exit 0 | |
fi | |
# 타임아웃 체크 | |
if [ $elapsed -ge $timeout ]; then | |
echo "Deployment verification timed out after ${timeout} seconds" | |
kubectl get pods -n default -l app=${{ env.MODULE }} | |
kubectl describe deployment ${{ env.MODULE }}-deployment -n default | |
exit 1 | |
fi | |
echo "Waiting for deployment to complete... (${elapsed}s elapsed)" | |
sleep $interval | |
elapsed=$((elapsed + interval)) | |
done | |
# - name: Clean up old images | |
# if: success() | |
# run: | | |
# kubectl exec -it $(kubectl get pods -l app=${{ env.MODULE }} -n ${{ env.NAMESPACE }} -o jsonpath='{.items[0].metadata.name}') -n ${{ env.NAMESPACE }} -- docker image prune -a -f |