Add Jenkinsfile and deploy script (build on NAS checkout, compose up -d).
docker-registry-aio/pipeline/head This commit looks good
docker-registry-aio/pipeline/head This commit looks good
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c7dad0ed0c
commit
421e8062e6
3 files changed
+132
No files matched your search
Vendored
+77
@@ -0,0 +1,77 @@
|
|||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
|
||||||
|
environment {
|
||||||
|
SSH_CONFIG_NAME = 'SEJONG-NAS'
|
||||||
|
DEPLOY_DIR = '/volume1/docker/docker-registry-aio'
|
||||||
|
}
|
||||||
|
|
||||||
|
options {
|
||||||
|
timestamps()
|
||||||
|
disableConcurrentBuilds()
|
||||||
|
buildDiscarder(logRotator(numToKeepStr: '20'))
|
||||||
|
}
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage('Validate') {
|
||||||
|
steps {
|
||||||
|
sh '''
|
||||||
|
set -eu
|
||||||
|
# No .env in the workspace: compose falls back to defaults, enough to check syntax.
|
||||||
|
docker compose config -q
|
||||||
|
sh -n scripts/deploy.sh
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Build') {
|
||||||
|
steps {
|
||||||
|
// Same Dockerfile the NAS builds; the agent shares the host daemon,
|
||||||
|
// so this also warms the build cache for the Deploy stage.
|
||||||
|
sh '''
|
||||||
|
set -eu
|
||||||
|
tag="registry-aio-app-ci:$(printf '%s' "$BUILD_TAG" | tr -c 'A-Za-z0-9_.-' '-' | cut -c1-128)"
|
||||||
|
trap 'docker image rm "$tag" >/dev/null 2>&1 || true' EXIT
|
||||||
|
docker build -t "$tag" app
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Deploy') {
|
||||||
|
when {
|
||||||
|
allOf {
|
||||||
|
not { changeRequest() }
|
||||||
|
anyOf {
|
||||||
|
branch 'main'
|
||||||
|
expression {
|
||||||
|
def branch = env.GIT_BRANCH ?: env.BRANCH_NAME ?: ''
|
||||||
|
branch == 'main' || branch == 'origin/main' || branch == 'refs/heads/main'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
steps {
|
||||||
|
// Keep the existing flow: the NAS checkout is the deployment.
|
||||||
|
// Fast-forward it to the built commit, then rebuild app and `compose up -d` there.
|
||||||
|
sshPublisher(
|
||||||
|
failOnError: true,
|
||||||
|
publishers: [
|
||||||
|
sshPublisherDesc(
|
||||||
|
configName: env.SSH_CONFIG_NAME,
|
||||||
|
verbose: true,
|
||||||
|
transfers: [
|
||||||
|
sshTransfer(
|
||||||
|
execTimeout: 1800000,
|
||||||
|
usePty: true,
|
||||||
|
execCommand: """
|
||||||
|
sudo -n su -c 'set -eu; export PATH=/usr/local/bin:/usr/bin:/bin; cd "${env.DEPLOY_DIR}"; git fetch -q origin main; git checkout -q main; git merge --ff-only "${env.GIT_COMMIT}"; sh scripts/deploy.sh'
|
||||||
|
""".stripIndent().trim()
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -158,3 +158,20 @@ config/registry/config.yml.template
|
|||||||
certs/ # compose certs 서비스가 자동 생성 (gitignore)
|
certs/ # compose certs 서비스가 자동 생성 (gitignore)
|
||||||
app/ # Nuxt + Prisma
|
app/ # Nuxt + Prisma
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Jenkins 배포
|
||||||
|
|
||||||
|
`Jenkinsfile`은 Gitea 멀티브랜치 파이프라인용입니다.
|
||||||
|
|
||||||
|
1. **Validate** — `docker compose config -q`, 배포 스크립트 문법 검사
|
||||||
|
2. **Build** — `app` 이미지를 빌드해 확인만 하고 지움 (모든 브랜치·PR)
|
||||||
|
3. **Deploy** — `main`만. SSH(`SEJONG-NAS`)로 배포 디렉터리의 체크아웃을 빌드한 커밋까지 fast-forward한 뒤 `scripts/deploy.sh` 실행
|
||||||
|
|
||||||
|
`scripts/deploy.sh`는 `app`을 다시 빌드하고 `docker compose up -d` 후 `app`이 healthy가 될 때까지 기다립니다.
|
||||||
|
수동 배포도 같은 스크립트를 씁니다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git pull --ff-only && sh scripts/deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
배포 디렉터리에 커밋되지 않은 수정이 있어 fast-forward가 안 되면 배포는 실패하고 아무것도 바뀌지 않습니다.
|
||||||
Executable
+38
@@ -0,0 +1,38 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Rebuild the app image from the current checkout and bring the stack up.
|
||||||
|
# Run from anywhere; used by the Jenkins Deploy stage and for manual deploys.
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
HEALTH_TIMEOUT="${HEALTH_TIMEOUT:-180}"
|
||||||
|
|
||||||
|
echo "deploy: $(git log -1 --format='%h %s' 2>/dev/null || echo unknown)"
|
||||||
|
|
||||||
|
docker compose config -q
|
||||||
|
docker compose build app
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
# registry's healthcheck always passes, so the app health is what tells us the deploy worked.
|
||||||
|
cid="$(docker compose ps -q app)"
|
||||||
|
elapsed=0
|
||||||
|
while :; do
|
||||||
|
status="$(docker inspect -f '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' "$cid")"
|
||||||
|
case "$status" in
|
||||||
|
healthy) break ;;
|
||||||
|
unhealthy|exited|dead)
|
||||||
|
echo "deploy: app is $status" >&2
|
||||||
|
docker compose logs --tail 50 app >&2
|
||||||
|
exit 1 ;;
|
||||||
|
esac
|
||||||
|
if [ "$elapsed" -ge "$HEALTH_TIMEOUT" ]; then
|
||||||
|
echo "deploy: app not healthy after ${HEALTH_TIMEOUT}s (status: $status)" >&2
|
||||||
|
docker compose logs --tail 50 app >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
sleep 5
|
||||||
|
elapsed=$((elapsed + 5))
|
||||||
|
done
|
||||||
|
|
||||||
|
docker compose ps
|
||||||
|
echo "deploy: done"
|
||||||
Reference in new issue
Block a user