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-jenkins', 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-jenkins', 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" ''' } } } } } } }