diff options
| author | 2026-07-30 10:59:45 +0700 | |
|---|---|---|
| committer | 2026-07-30 10:59:45 +0700 | |
| commit | f73435c674c0ef67bde106d3f953ace17d22a856 (patch) | |
| tree | 11c43abcfd67ca5223e61c954fe07a5d7b022d38 | |
| parent | 0d8fc1c94414f8e69cffe389620867a70ea85590 (diff) | |
| parent | 4bdcac0a88d0510df9cdef2e99bee20370fe219b (diff) | |
| download | web-0.17.3.2.tar.gz web-0.17.3.2.zip | |
ci: use self-hosted sayag.it jenkins
| -rw-r--r-- | .github/workflows/build-and-deploy-prod.yml | 103 | ||||
| -rw-r--r-- | .github/workflows/build-and-deploy-stage.yml | 104 | ||||
| -rw-r--r-- | Dockerfile | 9 | ||||
| -rw-r--r-- | Jenkinsfile | 313 | ||||
| -rw-r--r-- | deploy/playbook.yml | 8 |
5 files changed, 324 insertions, 213 deletions
diff --git a/.github/workflows/build-and-deploy-prod.yml b/.github/workflows/build-and-deploy-prod.yml deleted file mode 100644 index fc44571..0000000 --- a/.github/workflows/build-and-deploy-prod.yml +++ /dev/null @@ -1,103 +0,0 @@ -name: Docker image building and publishing onto Production -on: - push: - tags: - - "*" -jobs: - build-and-push: - if: github.repository == 'SayaAndy/saya-today-web' - runs-on: ubuntu-latest - environment: Production - permissions: - packages: write - steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: Generate output.css with tailwindcss - uses: ZoeyVid/tailwindcss-update@main - with: - input: static/input.css - output: static/output.css - params: "--minify" - - - name: Set up QEMU - uses: docker/setup-qemu-action@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v4 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GHCR_TOKEN }} - - - name: Build and push - uses: docker/build-push-action@v7 - with: - context: . - file: ./Dockerfile - push: true - cache-from: type=gha - cache-to: type=gha,mode=max - tags: | - ghcr.io/sayaandy/saya-today-web:latest - ghcr.io/sayaandy/saya-today-web:stable - ghcr.io/sayaandy/saya-today-web:${{ github.ref_name }} - - deploy: - if: github.repository == 'SayaAndy/saya-today-web' - runs-on: ubuntu-latest - environment: Production - needs: [build-and-push] - container: - image: ghcr.io/ansible/community-ansible-dev-tools:v26.4.6 - options: --user root - steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: Install community.docker collection - run: ansible-galaxy collection install community.docker - - - name: Set up SSH connection for uz.saya.casa - run: | - mkdir -p ~/.ssh - (cat <<EOF - ${{ secrets.SVC_GITHUB_PK }} - EOF - ) > ~/.ssh/id_ed25519 - chmod 600 ~/.ssh/id_ed25519 - sed -i 's/\r$//' ~/.ssh/id_ed25519 - ssh-keyscan -H uz.saya.casa >> ~/.ssh/known_hosts - - - name: Test SSH connection - run: | - ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 svc_github@uz.saya.casa "echo 'SSH connection successful'" - - - name: Run Ansible playbook - env: - ANSIBLE_HOST_KEY_CHECKING: "False" - working-directory: ./deploy - run: | - ansible-playbook \ - playbook.yml \ - -i inventory.yml \ - -l prod \ - --private-key ~/.ssh/id_ed25519 \ - -u svc_github \ - -e saya_today_web_auth_salt="${{ secrets.AUTH_SALT }}" \ - -e saya_today_web_s3_access_key_id="${{ secrets.S3_ACCESS_KEY_ID }}" \ - -e saya_today_web_s3_secret_access_key="${{ secrets.S3_SECRET_ACCESS_KEY }}" \ - -e saya_today_web_environment=prod \ - -e saya_today_web_tag=${{ github.ref_name }} \ - -e saya_today_web_mail_salt="${{ secrets.MAIL_SALT }}" \ - -e saya_today_web_mail_host="${{ secrets.MAIL_HOST }}" \ - -e saya_today_web_mail_address="${{ secrets.MAIL_ADDRESS }}" \ - -e saya_today_web_mail_username="${{ secrets.MAIL_USERNAME }}" \ - -e saya_today_web_mail_password="${{ secrets.MAIL_PASSWORD }}" \ - -e saya_today_google_site_verification="${{ secrets.GOOGLE_SITE_VERIFICATION }}" \ - -e saya_today_yandex_verification="${{ secrets.YANDEX_VERIFICATION }}" \ - -e saya_today_bing_verification="${{ secrets.BING_VERIFICATION }}" diff --git a/.github/workflows/build-and-deploy-stage.yml b/.github/workflows/build-and-deploy-stage.yml deleted file mode 100644 index ce4a1fb..0000000 --- a/.github/workflows/build-and-deploy-stage.yml +++ /dev/null @@ -1,104 +0,0 @@ -name: Docker image building and publishing onto Stage -on: - push: - branches: [stage] -jobs: - build-and-push: - if: github.repository == 'SayaAndy/saya-today-web' - runs-on: ubuntu-latest - environment: Stage - permissions: - packages: write - outputs: - sha_short: ${{ steps.ghss_vars.outputs.sha_short }} - steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: Generate output.css with tailwindcss - uses: ZoeyVid/tailwindcss-update@main - with: - input: static/input.css - output: static/output.css - params: "--minify" - - - name: Set up QEMU - uses: docker/setup-qemu-action@v4 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 - - - name: Login to GitHub Container Registry - uses: docker/login-action@v4 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GHCR_TOKEN }} - - - name: Set github short sha - id: ghss_vars - run: echo "sha_short=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT - - - name: Build and push - uses: docker/build-push-action@v7 - with: - context: . - file: ./Dockerfile - push: true - cache-from: type=gha - cache-to: type=gha,mode=max - tags: | - ghcr.io/sayaandy/saya-today-web:latest - ghcr.io/sayaandy/saya-today-web:commit-${{ steps.ghss_vars.outputs.sha_short }} - - deploy: - if: github.repository == 'SayaAndy/saya-today-web' - runs-on: ubuntu-latest - environment: Stage - needs: [build-and-push] - container: - image: ghcr.io/ansible/community-ansible-dev-tools:v26.4.6 - options: --user root - steps: - - name: Checkout - uses: actions/checkout@v6 - - - name: Install community.docker collection - run: ansible-galaxy collection install community.docker - - - name: Set up SSH connection for uz.saya.casa - run: | - mkdir -p ~/.ssh - (cat <<EOF - ${{ secrets.SVC_GITHUB_PK }} - EOF - ) > ~/.ssh/id_ed25519 - chmod 600 ~/.ssh/id_ed25519 - sed -i 's/\r$//' ~/.ssh/id_ed25519 - ssh-keyscan -H uz.saya.casa >> ~/.ssh/known_hosts - - - name: Test SSH connection - run: | - ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/id_ed25519 svc_github@uz.saya.casa "echo 'SSH connection successful'" - - - name: Run Ansible playbook - env: - ANSIBLE_HOST_KEY_CHECKING: "False" - working-directory: ./deploy - run: | - ansible-playbook \ - playbook.yml \ - -i inventory.yml \ - -l stage \ - --private-key ~/.ssh/id_ed25519 \ - -u svc_github \ - -e saya_today_web_auth_salt="${{ secrets.AUTH_SALT }}" \ - -e saya_today_web_s3_access_key_id="${{ secrets.S3_ACCESS_KEY_ID }}" \ - -e saya_today_web_s3_secret_access_key="${{ secrets.S3_SECRET_ACCESS_KEY }}" \ - -e saya_today_web_environment=stage \ - -e saya_today_web_tag=commit-${{ needs.build-and-push.outputs.sha_short }} \ - -e saya_today_web_mail_salt="${{ secrets.MAIL_SALT }}" \ - -e saya_today_web_mail_host="${{ secrets.MAIL_HOST }}" \ - -e saya_today_web_mail_address="${{ secrets.MAIL_ADDRESS }}" \ - -e saya_today_web_mail_username="${{ secrets.MAIL_USERNAME }}" \ - -e saya_today_web_mail_password="${{ secrets.MAIL_PASSWORD }}" @@ -1,4 +1,9 @@ -FROM golang:1.26-alpine3.23 AS build-stage +FROM golang:1.26.4-alpine3.24 AS build-stage + +ARG TARGETOS=linux +ARG TARGETARCH=amd64 +ENV GOOS=${TARGETOS} +ENV GOARCH=${TARGETARCH} RUN apk add --no-cache sqlite-dev musl-dev gcc @@ -7,7 +12,7 @@ COPY . . RUN go mod download RUN CGO_ENABLED=1 go build -o sayana-web . -FROM alpine:3.23 AS runtime-stage +FROM alpine:3.24 AS runtime-stage ENV ENVIRONMENT="" ENV AUTH_SALT="" diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..8633145 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,313 @@ +pipeline { + agent none + + stages { + stage('Compile Tailwind CSS') { + agent { + docker { + image 'node:26.3.1-alpine3.24' + args '-v /tmp:/tmp -v /.npm:/.npm' + } + } + steps { + checkout scm + sh ''' + npm install tailwindcss @tailwindcss/cli @tailwindcss/forms + npx tailwindcss -i static/input.css -o static/output.css --minify + ''' + stash name: 'tailwindcss-output', includes: 'static/output.css' + } + } + + stage('Matrix Build') { + matrix { + axes { + axis { + name 'GOOS' + values 'linux' + } + axis { + name 'GOARCH' + values 'arm64', 'amd64' + } + } + stages { + stage('Build') { + agent { + kubernetes { + defaultContainer 'kaniko' + yaml """ +apiVersion: v1 +kind: Pod +metadata: + namespace: jenkins +spec: + nodeSelector: + kubernetes.io/arch: ${GOARCH} + containers: + - name: kaniko + image: gcr.io/kaniko-project/executor:v1.24.0-debug + imagePullPolicy: Always + command: [ /busybox/cat ] + tty: true + resources: + requests: + cpu: "1" + memory: 2Gi + ephemeral-storage: 4Gi + limits: + memory: 4Gi + ephemeral-storage: 8Gi +""" + } + } + environment { + IMAGE_PUSH_DESTINATION="registry.sayag.it/sayauz/web" + } + steps { + checkout scm + unstash 'tailwindcss-output' + container(name: 'kaniko', shell: '/busybox/sh') { + withCredentials([string(credentialsId: 'registry-sayagit-jenkins-password', variable: 'REGISTRY_SAYAGIT_JENKINS_PASSWORD')]) { + withEnv(['PATH+EXTRA=/busybox']) { + script { + env.GIT_COMMIT_SHORT = env.GIT_COMMIT ? env.GIT_COMMIT.take(7) : "unknown" + try { + sh '''#!/busybox/sh + mkdir -p /kaniko/.docker + printf '{"auths":{"registry.sayag.it":{"username":"jenkins","password":"%s"}}}' "$REGISTRY_SAYAGIT_JENKINS_PASSWORD" > /kaniko/.docker/config.json + /kaniko/executor --context `pwd` \ + --custom-platform=linux/${GOARCH} \ + --build-arg TARGETOS=linux \ + --build-arg TARGETARCH=${GOARCH} \ + --destination $IMAGE_PUSH_DESTINATION:commit-$GIT_COMMIT_SHORT-$GOARCH + ''' + } catch (Exception e) { + echo "Caught exception: ${e.getMessage()}" + currentBuild.result = 'FAILURE' + throw e + } + } + } + } + } + } + } + } + } + } + stage('Stitch Manifest') { + agent { + kubernetes { + defaultContainer 'manifest-tool' + yaml """ +apiVersion: v1 +kind: Pod +metadata: + namespace: jenkins +spec: + containers: + - name: manifest-tool + image: mplatform/manifest-tool:alpine-v2.2.2 + imagePullPolicy: Always + command: [ 'cat' ] + tty: true + resources: + requests: + cpu: "1" + memory: 2Gi + ephemeral-storage: 4Gi +""" + } + } + environment { + IMAGE_PUSH_DESTINATION="registry.sayag.it/sayauz/web" + } + steps { + script { + env.GIT_COMMIT_SHORT = env.GIT_COMMIT ? env.GIT_COMMIT.take(7) : "unknown" + } + withCredentials([string(credentialsId: 'registry-sayagit-jenkins-password', variable: 'REGISTRY_SAYAGIT_JENKINS_PASSWORD')]) { + sh '''mkdir -p /root/.docker + printf '{"auths":{"registry.sayag.it":{"username":"jenkins","password":"%s"}}}' "$REGISTRY_SAYAGIT_JENKINS_PASSWORD" > /root/.docker/config.json + + manifest-tool push from-args \ + --platforms linux/amd64,linux/arm64 \ + --template $IMAGE_PUSH_DESTINATION:commit-$GIT_COMMIT_SHORT-ARCH \ + --target $IMAGE_PUSH_DESTINATION:commit-$GIT_COMMIT_SHORT + manifest-tool push from-args \ + --platforms linux/amd64,linux/arm64 \ + --template $IMAGE_PUSH_DESTINATION:commit-$GIT_COMMIT_SHORT-ARCH \ + --target $IMAGE_PUSH_DESTINATION:latest + if [ "$TAG_NAME" != "" ]; then + manifest-tool push from-args \ + --platforms linux/amd64,linux/arm64 \ + --template $IMAGE_PUSH_DESTINATION:commit-$GIT_COMMIT_SHORT-ARCH \ + --target $IMAGE_PUSH_DESTINATION:stable + manifest-tool push from-args \ + --platforms linux/amd64,linux/arm64 \ + --template $IMAGE_PUSH_DESTINATION:commit-$GIT_COMMIT_SHORT-ARCH \ + --target $IMAGE_PUSH_DESTINATION:$TAG_NAME + fi + ''' + } + } + } + stage('Deploy (Stage)') { + when { branch 'stage' } + agent { + kubernetes { + defaultContainer 'ansible' + yaml """ +apiVersion: v1 +kind: Pod +metadata: + namespace: jenkins +spec: + containers: + - name: ansible + image: ghcr.io/ansible/community-ansible-dev-tools:v26.7.2 + command: [ 'cat' ] + tty: true + resources: + requests: + cpu: "500m" + memory: 1Gi +""" + } + } + steps { + checkout scm + container('ansible') { + script { + env.GIT_COMMIT_SHORT = env.GIT_COMMIT ? env.GIT_COMMIT.take(7) : "unknown" + + def secretVars = [ + 'sayauz-web-stage-auth-salt' : 'AUTH_SALT', + 'sayauz-web-stage-s3-access-key-id' : 'S3_ACCESS_KEY_ID', + 'sayauz-web-stage-s3-secret-access-key' : 'S3_SECRET_ACCESS_KEY', + 'sayauz-web-stage-mail-salt' : 'MAIL_SALT', + 'sayauz-web-stage-mail-host' : 'MAIL_HOST', + 'sayauz-web-stage-mail-address' : 'MAIL_ADDRESS', + 'sayauz-web-stage-mail-username' : 'MAIL_USERNAME', + 'sayauz-web-stage-mail-password' : 'MAIL_PASSWORD' + ] + def bindings = secretVars.collect { id, varName -> string(credentialsId: id, variable: varName) } + bindings << sshUserPrivateKey(credentialsId: 'sayauz-svc-github', keyFileVariable: 'SSH_KEY_FILE', usernameVariable: 'SSH_USER') + + withCredentials(bindings) { + sh ''' + ansible-galaxy collection install community.docker + + mkdir -p ~/.ssh + cp "$SSH_KEY_FILE" ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + ssh-keyscan -H uz.saya.casa >> ~/.ssh/known_hosts + + ssh -o ConnectTimeout=10 -i ~/.ssh/id_ed25519 "$SSH_USER@uz.saya.casa" "echo 'SSH connection successful'" + + cd deploy + ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook \ + playbook.yml \ + -i inventory.yml \ + -l stage \ + --private-key ~/.ssh/id_ed25519 \ + -u "$SSH_USER" \ + -e saya_today_web_auth_salt="$AUTH_SALT" \ + -e saya_today_web_s3_access_key_id="$S3_ACCESS_KEY_ID" \ + -e saya_today_web_s3_secret_access_key="$S3_SECRET_ACCESS_KEY" \ + -e saya_today_web_environment=stage \ + -e saya_today_web_tag=commit-$GIT_COMMIT_SHORT \ + -e saya_today_web_mail_salt="$MAIL_SALT" \ + -e saya_today_web_mail_host="$MAIL_HOST" \ + -e saya_today_web_mail_address="$MAIL_ADDRESS" \ + -e saya_today_web_mail_username="$MAIL_USERNAME" \ + -e saya_today_web_mail_password="$MAIL_PASSWORD" + ''' + } + } + } + } + } + stage('Deploy (Prod)') { + when { buildingTag() } + agent { + kubernetes { + defaultContainer 'ansible' + yaml """ +apiVersion: v1 +kind: Pod +metadata: + namespace: jenkins +spec: + containers: + - name: ansible + image: ghcr.io/ansible/community-ansible-dev-tools:v26.7.2 + command: [ 'cat' ] + tty: true + resources: + requests: + cpu: "500m" + memory: 1Gi +""" + } + } + steps { + checkout scm + container('ansible') { + script { + def secretVars = [ + 'sayauz-web-prod-auth-salt' : 'AUTH_SALT', + 'sayauz-web-prod-s3-access-key-id' : 'S3_ACCESS_KEY_ID', + 'sayauz-web-prod-s3-secret-access-key' : 'S3_SECRET_ACCESS_KEY', + 'sayauz-web-prod-mail-salt' : 'MAIL_SALT', + 'sayauz-web-prod-mail-host' : 'MAIL_HOST', + 'sayauz-web-prod-mail-address' : 'MAIL_ADDRESS', + 'sayauz-web-prod-mail-username' : 'MAIL_USERNAME', + 'sayauz-web-prod-mail-password' : 'MAIL_PASSWORD', + 'sayauz-web-prod-verification-google' : 'GOOGLE_VERIFICATION', + 'sayauz-web-prod-verification-yandex' : 'YANDEX_VERIFICATION', + 'sayauz-web-prod-verification-bing' : 'BING_VERIFICATION' + ] + def bindings = secretVars.collect { id, varName -> string(credentialsId: id, variable: varName) } + bindings << sshUserPrivateKey(credentialsId: 'sayauz-svc-github', keyFileVariable: 'SSH_KEY_FILE', usernameVariable: 'SSH_USER') + + withCredentials(bindings) { + sh ''' + ansible-galaxy collection install community.docker + + mkdir -p ~/.ssh + cp "$SSH_KEY_FILE" ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + ssh-keyscan -H uz.saya.casa >> ~/.ssh/known_hosts + + ssh -o ConnectTimeout=10 -i ~/.ssh/id_ed25519 "$SSH_USER@uz.saya.casa" "echo 'SSH connection successful'" + + cd deploy + ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook \ + playbook.yml \ + -i inventory.yml \ + -l prod \ + --private-key ~/.ssh/id_ed25519 \ + -u "$SSH_USER" \ + -e saya_today_web_auth_salt="$AUTH_SALT" \ + -e saya_today_web_s3_access_key_id="$S3_ACCESS_KEY_ID" \ + -e saya_today_web_s3_secret_access_key="$S3_SECRET_ACCESS_KEY" \ + -e saya_today_web_environment=prod \ + -e saya_today_web_tag=$TAG_NAME \ + -e saya_today_web_mail_salt="$MAIL_SALT" \ + -e saya_today_web_mail_host="$MAIL_HOST" \ + -e saya_today_web_mail_address="$MAIL_ADDRESS" \ + -e saya_today_web_mail_username="$MAIL_USERNAME" \ + -e saya_today_web_mail_password="$MAIL_PASSWORD" \ + -e saya_today_google_verification="$GOOGLE_VERIFICATION" \ + -e saya_today_yandex_verification="$YANDEX_VERIFICATION" \ + -e saya_today_bing_verification="$BING_VERIFICATION" + ''' + } + } + } + } + } + } +} diff --git a/deploy/playbook.yml b/deploy/playbook.yml index f725335..057cc19 100644 --- a/deploy/playbook.yml +++ b/deploy/playbook.yml @@ -6,7 +6,7 @@ vars: docker_volumes: - "{{ saya_today_web_name }}-volume:/data:rw" - + tasks: - name: Initialize Unix socket volume when: >- @@ -26,11 +26,11 @@ community.docker.docker_volume: name: "{{ saya_today_web_name }}-volume" - - name: Deploy saya-today-web Docker Container + - name: Deploy sayauz/web Docker Container community.docker.docker_container: name: "{{ saya_today_web_name }}" hostname: "{{ saya_today_web_hostname }}" - image: "ghcr.io/sayaandy/saya-today-web:{{ saya_today_web_tag }}" + image: "registry.sayag.it/sayauz/web:{{ saya_today_web_tag }}" env: S3_ACCESS_KEY_ID: "{{ saya_today_web_s3_access_key_id }}" S3_SECRET_ACCESS_KEY: "{{ saya_today_web_s3_secret_access_key }}" @@ -42,7 +42,7 @@ MAIL_PASSWORD: "{{ saya_today_web_mail_password }}" MAIL_SALT: "{{ saya_today_web_mail_salt }}" FQDN: "{{ saya_today_web_listen_address }}" - GOOGLE_SITE_VERIFICATION: "{{ saya_today_google_site_verification | default('') }}" + GOOGLE_VERIFICATION: "{{ saya_today_google_verification | default('') }}" YANDEX_VERIFICATION: "{{ saya_today_yandex_verification | default('') }}" BING_VERIFICATION: "{{ saya_today_bing_verification | default('') }}" network_mode: caddy |