Jenkins
Architecture
graph TD
classDef blue fill:#3498db,stroke:#2980b9,color:#fff
classDef green fill:#2ecc71,stroke:#27ae60,color:#fff
classDef red fill:#e74c3c,stroke:#c0392b,color:#fff
classDef orange fill:#e67e22,stroke:#d35400,color:#fff
classDef purple fill:#9b59b6,stroke:#8e44ad,color:#fff
classDef teal fill:#1abc9c,stroke:#16a085,color:#fff
classDef dark fill:#2c3e50,stroke:#1a252f,color:#fff
classDef yellow fill:#f39c12,stroke:#d68910,color:#000
classDef k8s fill:#326ce5,stroke:#254ea8,color:#fff
classDef aws fill:#ff9900,stroke:#cc7a00,color:#000
CONTROLLER["Jenkins Controller (master) Orchestrates jobs, stores config, UI"]:::purple --> AGENT1["Agent 1 (docker)"]:::blue
CONTROLLER --> AGENT2["Agent 2 (kubernetes pod)"]:::k8s
CONTROLLER --> AGENT3["Agent 3 (EC2 spot instance)"]:::orange
subgraph Job["Pipeline Job"]
SCM["Poll SCM or webhook trigger"]:::orange --> CHECKOUT["Checkout from git"]:::green
CHECKOUT --> STAGES["Run stages on agent"]:::blue
STAGES --> ARCHIVE["Archive artifacts / publish results"]:::green
end
Key concepts:
- Controller — the Jenkins server: schedules jobs, stores state, serves UI. Never run builds on the controller itself.
- Agent — worker nodes where builds actually run. Can be static (always-on EC2) or dynamic (K8s pod spawned per build, deleted when done).
- Executor — a slot on an agent. One executor = one concurrent build on that agent.
Declarative Pipeline
pipeline {
// Where to run — any available agent, or specify label
agent { label 'docker' }
// Environment variables available to all stages
environment {
APP_NAME = "my-service"
ECR_REPO = "123456789.dkr.ecr.us-east-1.amazonaws.com/my-service"
}
// Build parameters — shown in UI, passed to builds
parameters {
string(name: 'ENVIRONMENT', defaultValue: 'staging', description: 'Target environment')
choice(name: 'REGION', choices: ['us-east-1', 'eu-west-1'], description: 'AWS Region')
booleanParam(name: 'DRY_RUN', defaultValue: false, description: 'Skip actual deploy')
}
stages {
stage('Build') {
steps {
sh 'docker build -t ${APP_NAME}:${BUILD_NUMBER} .'
}
}
stage('Test') {
steps {
sh 'go test ./...'
}
post {
always {
publishTestResults testResultsPattern: 'test-results/*.xml'
}
}
}
stage('Deploy') {
when {
expression { params.DRY_RUN == false }
}
steps {
sh "deploy.sh --env ${params.ENVIRONMENT} --region ${params.REGION}"
}
}
}
post {
success { slackSend message: "Build ${BUILD_NUMBER} succeeded" }
failure { slackSend message: "Build ${BUILD_NUMBER} FAILED" }
}
}
Dynamic Variables and Script Block
// Set variables during pipeline execution using script block
stage('Get Version') {
steps {
script {
// sh with returnStdout captures output as string
def gitTag = sh(returnStdout: true, script: 'git describe --tags --abbrev=0').trim()
def gitSha = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
// Set as env vars — available to all subsequent stages
env.APP_VERSION = gitTag ?: "dev-${gitSha}"
env.DOCKER_TAG = "${env.APP_VERSION}-${env.BUILD_NUMBER}"
}
}
}
stage('Build Image') {
steps {
// Use the dynamically set variable
sh "docker build -t ${ECR_REPO}:${env.DOCKER_TAG} ."
}
}
withCredentials — Secrets Injection
Secrets are stored in Jenkins Credentials store, never in Jenkinsfile. withCredentials injects them as env vars, auto-masked in all logs.
stage('Deploy to AWS') {
steps {
withCredentials([
// Single string secret (API key, token)
string(credentialsId: 'SLACK_WEBHOOK', variable: 'SLACK_URL'),
// Username + password (Docker registry, DB)
usernamePassword(
credentialsId: 'ECR_CREDENTIALS',
usernameVariable: 'AWS_ACCESS_KEY_ID',
passwordVariable: 'AWS_SECRET_ACCESS_KEY'
),
// SSH key (deploy to server)
sshUserPrivateKey(
credentialsId: 'DEPLOY_SSH_KEY',
keyFileVariable: 'SSH_KEY_FILE'
)
]) {
sh '''
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin $ECR_REPO
docker push $ECR_REPO:$DOCKER_TAG
'''
// $SLACK_URL and AWS credentials are masked in logs — shown as ****
}
}
}
Shared Libraries
Shared libraries let you define common functions once and reuse them across all pipelines. Stored in a separate git repo.
jenkins-shared-library/
├── vars/
│ ├── deployToECS.groovy # global function: deployToECS(...)
│ └── runGoTests.groovy # global function: runGoTests()
└── src/
└── org/company/
└── Utils.groovy # class-based helpers
// vars/deployToECS.groovy
def call(Map config) {
def env = config.environment ?: 'staging'
def service = config.service
def image = config.image
sh "aws ecs update-service --cluster ${env} --service ${service} --force-new-deployment"
sh "aws ecs wait services-stable --cluster ${env} --services ${service}"
echo "Deployed ${image} to ${service} in ${env}"
}
// Jenkinsfile in any repo — import the shared library
@Library('jenkins-shared-library') _
pipeline {
agent any
stages {
stage('Deploy') {
steps {
// Call the shared library function
deployToECS(
environment: 'production',
service: 'my-service',
image: "${ECR_REPO}:${env.DOCKER_TAG}"
)
}
}
}
}
Pipeline Patterns
Matrix builds (test across multiple versions)
stage('Test Matrix') {
matrix {
axes {
axis { name 'GO_VERSION'; values '1.21', '1.22', '1.23' }
axis { name 'OS'; values 'linux', 'darwin' }
}
stages {
stage('Test') {
steps {
sh "GOOS=${OS} go test ./..."
}
}
}
}
}
Parallel stages
stage('Test and Scan') {
parallel {
stage('Unit Tests') { steps { sh 'go test ./...' } }
stage('Security Scan') { steps { sh 'trivy image ${APP_NAME}:${BUILD_NUMBER}' } }
stage('Lint') { steps { sh 'golangci-lint run ./...' } }
}
}
Manual approval gate
stage('Deploy to Production') {
input {
message "Deploy ${env.APP_VERSION} to production?"
ok "Deploy"
parameters {
string(name: 'DEPLOY_NOTE', defaultValue: '', description: 'Deployment note')
}
}
steps {
sh "deploy.sh --env prod"
}
}
Jenkins on AWS ECS: Master-Agent Architecture
For the deep-dive into running Jenkins agents as ECS tasks (Fargate + EC2 launch types), including:
- How the inbound agent JNLP protocol works internally
- ECS task provisioning flow (sequence diagrams)
- Scaling mechanics (1 job = 1 ECS task)
- Custom Docker images per job type
- 60% cost reduction and 50% build time improvement breakdown
- Fargate vs EC2 decision matrix, SOCI, Golden AMI, S3 caching
See ecs-agents.md.