chore: add v0.8.0 doc (#845)

This commit is contained in:
Luigi Operoso 2023-06-05 22:54:54 +02:00 committed by GitHub
parent d9ea2ee83b
commit 4e5f9d562f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 5396 additions and 16 deletions

View File

@ -2,7 +2,7 @@
title: "Getting Started" title: "Getting Started"
linkTitle: "Getting Started" linkTitle: "Getting Started"
weight: 2 weight: 2
date: 2021-08-19 date: 2023-06-04
description: > description: >
How to work with Jenkins Operator How to work with Jenkins Operator
--- ---

View File

@ -1,19 +1,19 @@
--- ---
title: "Latest (v0.7.x)" title: "Latest (v0.8.x)"
linkTitle: "Latest (v0.7.x)" linkTitle: "Latest (v0.8.x)"
weight: 1 weight: 1
date: 2021-12-08 date: 2023-31-05
description: > description: >
How to work with the latest, currently supported Jenkins Operator version. How to work with the latest, currently supported Jenkins Operator version.
--- ---
{{% pageinfo %}} {{% pageinfo %}}
This document describes a getting started guide for **Jenkins Operator** `v0.7.x` and also additional configuration. This document describes a getting started guide for **Jenkins Operator** `v0.8.x` and also additional configuration.
{{% /pageinfo %}} {{% /pageinfo %}}
## First Steps ## First Steps
Prepare your Kubernetes cluster and set up your `kubectl` access. Prepare your Kubernetes cluster and set up your `kubectl` access.
Once you have a running Kubernetes cluster you can focus on installing **Jenkins Operator** according to the Once you have a running Kubernetes cluster you can focus on installing **Jenkins Operator** according to the
[Installation](/kubernetes-operator/docs/getting-started/latest/installing-the-operator/) guide. [Installation](/kubernetes-operator/docs/getting-started/latest/installing-the-operator/) guide.

View File

@ -7,8 +7,8 @@ description: >
Prevent loss of job history Prevent loss of job history
--- ---
> Because of Jenkins Operator's architecture, the configuration of Jenkins should be done using ConfigurationAsCode > Because of Jenkins Operator's architecture, the configuration of Jenkins should be done using ConfigurationAsCode
> or GroovyScripts and jobs should be defined as SeedJobs. It means that there is no point in backing up any job configuration > or GroovyScripts and jobs should be defined as SeedJobs. It means that there is no point in backing up any job configuration
> up. Therefore, the backup script makes a copy of jobs history only. > up. Therefore, the backup script makes a copy of jobs history only.
Backup and restore is done by a container sidecar. Backup and restore is done by a container sidecar.
@ -54,7 +54,7 @@ spec:
disableCSRFProtection: false disableCSRFProtection: false
containers: containers:
- name: jenkins-master - name: jenkins-master
image: jenkins/jenkins:2.277.4-lts-alpine image: jenkins/jenkins:2.401.1-lts
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
resources: resources:
limits: limits:
@ -71,7 +71,7 @@ spec:
value: /jenkins-home value: /jenkins-home
- name: BACKUP_COUNT - name: BACKUP_COUNT
value: "3" # keep only the 2 most recent backups value: "3" # keep only the 2 most recent backups
image: virtuslab/jenkins-operator-backup-pvc:v0.1.1 # look at backup/pvc directory image: quay.io/jenkins-kubernetes-operator/backup-pvc:v0.2.3 # look at backup/pvc directory
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
volumeMounts: volumeMounts:
- mountPath: /jenkins-home # Jenkins home volume - mountPath: /jenkins-home # Jenkins home volume

View File

@ -14,7 +14,7 @@ This document describes the procedure for deploying Jenkins.
## Prerequisites ## Prerequisites
The Operator needs to have been deployed beforehand. The procedure for deploying Jenkins described here doesn't apply to The Operator needs to have been deployed beforehand. The procedure for deploying Jenkins described here doesn't apply to
installation of Operator via Helm chart unless `jenkins.enabled` was set to false. installation of Operator via Helm chart unless `jenkins.enabled` was set to false.
Thats because by default, installation via Helm chart also covers deploying Jenkins. Thats because by default, installation via Helm chart also covers deploying Jenkins.
@ -43,7 +43,7 @@ spec:
disableCSRFProtection: false disableCSRFProtection: false
containers: containers:
- name: jenkins-master - name: jenkins-master
image: jenkins/jenkins:2.319.1-lts-alpine image: jenkins/jenkins:2.401.1-lts
imagePullPolicy: Always imagePullPolicy: Always
livenessProbe: livenessProbe:
failureThreshold: 12 failureThreshold: 12

View File

@ -941,7 +941,7 @@ spec:
args: args:
- --leader-elect - --leader-elect
<b>- --validate-security-warnings</b> <b>- --validate-security-warnings</b>
image: virtuslab/jenkins-operator:v0.7.0 image: quay.io/jenkins-kubernetes-operator/operator:v0.8.0
name: jenkins-operator name: jenkins-operator
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
securityContext: securityContext:

View File

@ -7,4 +7,6 @@ description: >
Additional configuration for OpenShift Additional configuration for OpenShift
--- ---
## Release 0.7.0 is not compatible with OpenShift. ## Release 0.8.0 is not compatible with jenkins image shipped by redhat in OpenShift.
But probably it will run correctly with the jenkins lts version. If you find any issue please report it here: https://github.com/jenkinsci/kubernetes-operator/issues/826.

View File

@ -281,7 +281,7 @@ spec:
- /manager - /manager
args: args:
- --leader-elect - --leader-elect
image: virtuslab/jenkins-operator:v0.7.0 image: image: quay.io/jenkins-kubernetes-operator/operator:v0.8.0
name: jenkins-operator name: jenkins-operator
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
securityContext: securityContext:
@ -536,7 +536,7 @@ spec:
disableCSRFProtection: false disableCSRFProtection: false
containers: containers:
- name: jenkins-master - name: jenkins-master
image: jenkins/jenkins:2.319.1-lts-alpine image: jenkins/jenkins:2.401.1-lts
imagePullPolicy: Always imagePullPolicy: Always
livenessProbe: livenessProbe:
failureThreshold: 12 failureThreshold: 12

View File

@ -0,0 +1,19 @@
---
title: "Latest (v0.8.x)"
linkTitle: "Latest (v0.8.x)"
weight: 1
date: 2021-12-08
description: >
How to work with the latest, currently supported Jenkins Operator version.
---
{{% pageinfo %}}
This document describes a getting started guide for **Jenkins Operator** `v0.8.x` and also additional configuration.
{{% /pageinfo %}}
## First Steps
Prepare your Kubernetes cluster and set up your `kubectl` access.
Once you have a running Kubernetes cluster you can focus on installing **Jenkins Operator** according to the
[Installation](/kubernetes-operator/docs/getting-started/latest/installing-the-operator/) guide.

View File

@ -0,0 +1,24 @@
---
title: "AKS"
linkTitle: "AKS"
weight: 8
date: 2021-12-08
description: >
Additional configuration for Azure Kubernetes Service
---
Azure AKS managed Kubernetes service adds to every pod the following environment variables:
```yaml
- name: KUBERNETES_PORT_443_TCP_ADDR
value:
- name: KUBERNETES_PORT
value: tcp://
- name: KUBERNETES_PORT_443_TCP
value: tcp://
- name: KUBERNETES_SERVICE_HOST
value:
```
The operator is aware of it and omits these environment variables when checking if a Jenkins pod environment has been changed. It prevents the
restart of a Jenkins pod over and over again.

View File

@ -0,0 +1,111 @@
---
title: "Configuring backup and restore"
linkTitle: "Configuring backup and restore"
weight: 5
date: 2023-01-08
description: >
Prevent loss of job history
---
> Because of Jenkins Operator's architecture, the configuration of Jenkins should be done using ConfigurationAsCode
> or GroovyScripts and jobs should be defined as SeedJobs. It means that there is no point in backing up any job configuration
> up. Therefore, the backup script makes a copy of jobs history only.
Backup and restore is done by a container sidecar.
### PVC
#### Create PVC
Save to the file named pvc.yaml:
```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: <pvc_name>
namespace: <namespace>
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Gi
```
Run the following command:
```bash
$ kubectl -n <namespace> create -f pvc.yaml
```
#### Configure Jenkins CR
```yaml
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: jenkins-cr
spec:
jenkinsAPISettings:
authorizationStrategy: createUser
master:
securityContext:
runAsUser: 1000
fsGroup: 1000
disableCSRFProtection: false
containers:
- name: jenkins-master
image: jenkins/jenkins:2.277.4-lts-alpine
imagePullPolicy: IfNotPresent
resources:
limits:
cpu: 1500m
memory: 3Gi
requests:
cpu: "1"
memory: 500Mi
- name: backup # container responsible for the backup and restore
env:
- name: BACKUP_DIR
value: /backup
- name: JENKINS_HOME
value: /jenkins-home
- name: BACKUP_COUNT
value: "3" # keep only the 2 most recent backups
image: virtuslab/jenkins-operator-backup-pvc:v0.1.1 # look at backup/pvc directory
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /jenkins-home # Jenkins home volume
name: jenkins-home
- mountPath: /backup # backup volume
name: backup
resources:
limits:
cpu: 1000m
memory: 3Gi
requests:
cpu: "1"
memory: 500Mi
volumes:
- name: backup # PVC volume where backups will be stored
persistentVolumeClaim:
claimName: <pvc_name>
backup:
containerName: backup # container name is responsible for backup
action:
exec:
command:
- /home/user/bin/backup.sh # this command is invoked on "backup" container to make backup, for example /home/user/bin/backup.sh <backup_number>, <backup_number> is passed by operator
interval: 30 # how often make backup in seconds
makeBackupBeforePodDeletion: true # make a backup before pod deletion
restore:
containerName: backup # container name is responsible for restore backup
action:
exec:
command:
- /home/user/bin/restore.sh # this command is invoked on "backup" container to make restore backup, for example /home/user/bin/restore.sh <backup_number>, <backup_number> is passed by operator
#recoveryOnce: <backup_number> # if want to restore specific backup configure this field and then Jenkins will be restarted and desired backup will be restored
getLatestAction:
exec:
command:
- /home/user/bin/get-latest.sh # this command is invoked on "backup" container to get last backup number before pod deletion; not having it in the CR may cause loss of data
```

View File

@ -0,0 +1,336 @@
---
title: "Configuring Seed Jobs and Pipelines"
linkTitle: "Configuring Seed Jobs and Pipelines"
weight: 4
date: 2021-12-08
description: >
How to configure Jenkins with Operator
---
## Configure Seed Jobs and Pipelines
Jenkins operator uses [job-dsl][job-dsl] and [kubernetes-credentials-provider][kubernetes-credentials-provider] plugins for configuring jobs
and deploy keys.
## Prepare job definitions and pipelines
First you have to prepare pipelines and job definition in your GitHub repository using the following structure:
```
cicd/
├── jobs
│   └── k8s.jenkins
└── pipelines
└── k8s.jenkins
```
**`cicd/jobs/k8s.jenkins`** is a job definition:
```
#!/usr/bin/env groovy
pipelineJob('k8s-e2e') {
displayName('Kubernetes Plugin E2E Test')
logRotator {
numToKeep(10)
daysToKeep(30)
}
configure { project ->
project / 'properties' / 'org.jenkinsci.plugins.workflow.job.properties.DurabilityHintJobProperty' {
hint('PERFORMANCE_OPTIMIZED')
}
}
definition {
cpsScm {
scm {
git {
remote {
url('https://github.com/jenkinsci/kubernetes-operator.git')
credentials('jenkins-operator')
}
branches('*/master')
}
}
scriptPath('cicd/pipelines/k8s.jenkins')
}
}
}
```
**`cicd/pipelines/k8s.jenkins`** is an actual Jenkins pipeline:
```
#!/usr/bin/env groovy
def label = "k8s-${UUID.randomUUID().toString()}"
def home = "/home/jenkins"
def workspace = "${home}/workspace/build-jenkins-operator"
def workdir = "${workspace}/src/github.com/jenkinsci/kubernetes-operator/"
podTemplate(label: label,
containers: [
containerTemplate(name: 'alpine', image: 'alpine:3.11', ttyEnabled: true, command: 'cat'),
],
) {
node(label) {
stage('Run shell') {
container('alpine') {
sh 'echo "hello world"'
}
}
}
}
```
## Configure Seed Jobs
Jenkins Seed Jobs are configured using `Jenkins.spec.seedJobs` section from your custom resource manifest:
```
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
spec:
seedJobs:
- id: jenkins-operator
targets: "cicd/jobs/*.jenkins"
description: "Jenkins Operator repository"
repositoryBranch: master
repositoryUrl: https://github.com/jenkinsci/kubernetes-operator.git
```
**Jenkins Operator** will automatically discover and configure all the seed jobs.
You can verify if deploy keys were successfully configured in the Jenkins **Credentials** tab.
![jenkins](/kubernetes-operator/img/jenkins-credentials.png)
You can verify if your pipelines were successfully configured in the Jenkins Seed Job console output.
![jenkins](/kubernetes-operator/img/jenkins-seed.png)
If your GitHub repository is **private** you have to configure SSH or username/password authentication.
### SSH authentication
#### Generate SSH Keys
There are two methods of SSH private key generation:
```bash
$ openssl genrsa -out <filename> 2048
```
or
```bash
$ ssh-keygen -t rsa -b 2048
$ ssh-keygen -p -f <filename> -m pem
```
Then copy content from generated file.
#### Public key
If you want to upload your public key to your Git server you need to extract it.
If key was generated by `openssl` then you need to type this to extract public key:
```bash
$ openssl rsa -in <filename> -pubout > <filename>.pub
```
If key was generated by `ssh-keygen` the public key content is located in <filename>.pub and there is no need to extract public key
#### Configure SSH authentication
Configure a seed job like this:
```
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
spec:
seedJobs:
- id: jenkins-operator-ssh
credentialType: basicSSHUserPrivateKey
credentialID: k8s-ssh
targets: "cicd/jobs/*.jenkins"
description: "Jenkins Operator repository"
repositoryBranch: master
repositoryUrl: git@github.com:jenkinsci/kubernetes-operator.git
```
and create a Kubernetes Secret (name of secret should be the same from `credentialID` field):
```
apiVersion: v1
kind: Secret
metadata:
name: k8s-ssh
labels:
"jenkins.io/credentials-type": "basicSSHUserPrivateKey"
annotations:
"jenkins.io/credentials-description" : "ssh github.com:jenkinsci/kubernetes-operator"
stringData:
privateKey: |
-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEAxxDpleJjMCN5nusfW/AtBAZhx8UVVlhhhIKXvQ+dFODQIdzO
oDXybs1zVHWOj31zqbbJnsfsVZ9Uf3p9k6xpJ3WFY9b85WasqTDN1xmSd6swD4N8
...
username: github_user_name
```
### Username & password authentication
Configure the seed job like:
```
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
spec:
seedJobs:
- id: jenkins-operator-user-pass
credentialType: usernamePassword
credentialID: k8s-user-pass
targets: "cicd/jobs/*.jenkins"
description: "Jenkins Operator repository"
repositoryBranch: master
repositoryUrl: https://github.com/jenkinsci/kubernetes-operator.git
```
and create a Kubernetes Secret (name of secret should be the same from `credentialID` field):
```
apiVersion: v1
kind: Secret
metadata:
name: k8s-user-pass
stringData:
username: github_user_name
password: password_or_token
```
### External authentication
You can use `external` credential type if you want to configure authentication using Configuration As Code or Groovy Script.
Example:
```yaml
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
spec:
seedJobs:
- id: jenkins-operator-external
credentialType: external
credentialID: k8s-external
targets: "cicd/jobs/*.jenkins"
description: "Jenkins Operator repository"
repositoryBranch: master
repositoryUrl: https://github.com/jenkinsci/kubernetes-operator.git
```
Remember that `credentialID` must match the id of the credentials configured in Jenkins. Consult the
[Jenkins docs for using credentials][jenkins-using-credentials] for details.
## HTTP Proxy for downloading plugins
To use forwarding proxy with an operator to download plugins you need to add the following environment variable to Jenkins Custom Resource (CR), e.g.:
```yaml
spec:
master:
containers:
- name: jenkins-master
env:
- name: CURL_OPTIONS
value: -L -x <proxy_url>
```
In `CURL_OPTIONS` var you can set additional arguments to `curl` command.
## Pulling Docker images from private repositories
To pull a Docker Image from private repository you can use `imagePullSecrets`.
Please follow the instructions on [creating a secret with a docker config](https://kubernetes.io/docs/concepts/containers/images/?origin_team=T42NTAGHM#creating-a-secret-with-a-docker-config).
### Docker Hub Configuration
To use Docker Hub additional steps are required.
Edit the previously created secret:
```bash
kubectl -n <namespace> edit secret <name>
```
The `.dockerconfigjson` key's value needs to be replaced with a modified version.
After modifications, it needs to be encoded as a Base64 value before setting the `.dockerconfigjson` key.
Example config file to modify and use:
```
{
"auths":{
"https://index.docker.io/v1/":{
"username":"user",
"password":"password",
"email":"yourdockeremail@gmail.com",
"auth":"base64 of string user:password"
},
"auth.docker.io":{
"username":"user",
"password":"password",
"email":"yourdockeremail@gmail.com",
"auth":"base64 of string user:password"
},
"registry.docker.io":{
"username":"user",
"password":"password",
"email":"yourdockeremail@gmail.com",
"auth":"base64 of string user:password"
},
"docker.io":{
"username":"user",
"password":"password",
"email":"yourdockeremail@gmail.com",
"auth":"base64 of string user:password"
},
"https://registry-1.docker.io/v2/": {
"username":"user",
"password":"password",
"email":"yourdockeremail@gmail.com",
"auth":"base64 of string user:password"
},
"registry-1.docker.io/v2/": {
"username":"user",
"password":"password",
"email":"yourdockeremail@gmail.com",
"auth":"base64 of string user:password"
},
"registry-1.docker.io": {
"username":"user",
"password":"password",
"email":"yourdockeremail@gmail.com",
"auth":"base64 of string user:password"
},
"https://registry-1.docker.io": {
"username":"user",
"password":"password",
"email":"yourdockeremail@gmail.com",
"auth":"base64 of string user:password"
}
}
}
```
[job-dsl]:https://github.com/jenkinsci/job-dsl-plugin
[kubernetes-credentials-provider]:https://jenkinsci.github.io/kubernetes-credentials-provider-plugin/
[jenkins-using-credentials]:https://www.jenkins.io/doc/book/using/using-credentials/

View File

@ -0,0 +1,184 @@
---
title: "Custom backup and restore providers"
linkTitle: "Custom backup and restore providers"
weight: 7
date: 2021-12-08
description: >
Custom backup and restore provider
---
With enough effort one can create a custom backup and restore provider
for the Jenkins Operator.
## Requirements
Two commands (e.g. scripts) are required:
- a backup command, e.g. `backup.sh` that takes one argument, a **backup number**
- a restore command, e.g. `backup.sh` that takes one argument, a **backup number**
Both scripts need to return an exit code of `0` on success and `1` or greater for failure.
One of those scripts (or the entry point of the container) needs to be responsible
for backup cleanup or rotation if required, or an external system.
## How it works
The mechanism relies on basic Kubernetes and UNIX functionalities.
The backup (and restore) container runs as a sidecar in the same
Kubernetes pod as the Jenkins master.
Name of the backup and restore containers can be set as necessary using
`spec.backup.containerName` and `spec.restore.containerName`.
In most cases it will be the same container, but we allow for less common use cases.
The operator will call a backup or restore commands inside a sidecar container when necessary:
- backup command (defined in `spec.backup.action.exec.command`)
will be called every `N` seconds configurable in: `spec.backup.interval`
and on pod shutdown (if enabled in `spec.backup.makeBackupBeforePodDeletion`)
with an integer representing the current backup number as first and only argument
- restore command (defined in `spec.restore.action.exec.command`)
will be called at Jenkins startup
with an integer representing the backup number to restore as first and only argument
(can be overridden using `spec.restore.recoveryOnce`)
## Example AWS S3 backup using the CLI
This example shows abbreviated version of a simple AWS S3 backup implementation
using: `aws-cli`, `bash` and `kube2iam`.
In addition to your normal `Jenkins` `CustomResource` some additional settings
for backup and restore are required, e.g.:
```yaml
kind: Jenkins
apiVersion: jenkins.io/v1alpha1
metadata:
name: example
namespace: jenkins
spec:
master:
masterAnnotations:
iam.amazonaws.com/role: "my-example-backup-role" # tell kube2iam where the AWS IAM role is
containers:
- name: jenkins-master
...
- name: backup # container responsible for backup and restore
image: quay.io/virtuslab/aws-cli:1.16.263-2
workingDir: /home/user/bin/
command: # our container entry point
- sleep
- infinity
env:
- name: BACKUP_BUCKET
value: my-example-bucket # the S3 bucket name to use
- name: BACKUP_PATH
value: my-backup-path # the S3 bucket path prefix to use
- name: JENKINS_HOME
value: /jenkins-home # the path to mount jenkins home dir in the backup container
volumeMounts:
- mountPath: /jenkins-home # Jenkins home volume
name: jenkins-home
- mountPath: /home/user/bin/backup.sh
name: backup-scripts
subPath: backup.sh
readOnly: true
- mountPath: /home/user/bin/restore.sh
name: backup-scripts
subPath: restore.sh
readOnly: true
volumes:
- name: backup-scripts
configMap:
defaultMode: 0754
name: jenkins-operator-backup-s3
securityContext: # make sure both containers use the same UID and GUID
runAsUser: 1000
fsGroup: 1000
...
backup:
containerName: backup # container name responsible for backup
interval: 3600 # how often make a backup in seconds
makeBackupBeforePodDeletion: true # trigger backup just before deleting the pod
action:
exec:
command:
# this command is invoked on "backup" container to create a backup,
# <backup_number> is passed by operator,
# for example /home/user/bin/backup.sh <backup_number>
- /home/user/bin/backup.sh
restore:
containerName: backup # container name is responsible for restore backup
action:
exec:
command:
# this command is invoked on "backup" container to restore a backup,
# <backup_number> is passed by operator
# for example /home/user/bin/restore.sh <backup_number>
- /home/user/bin/restore.sh
# recoveryOnce: <backup_number> # if want to restore specific backup configure this field and then Jenkins will be restarted and desired backup will be restored
```
The actual backup and restore scripts will be provided in a `ConfigMap`:
```yaml
kind: ConfigMap
apiVersion: v1
metadata:
name: jenkins-operator-backup-s3
namespace: jenkins
labels:
app: jenkins-operator
data:
backup.sh: |-
#!/bin/bash -xeu
[[ ! $# -eq 1 ]] && echo "Usage: $0 backup_number" && exit 1;
[[ -z "${BACKUP_BUCKET}" ]] && echo "Required 'BACKUP_BUCKET' env not set" && exit 1;
[[ -z "${BACKUP_PATH}" ]] && echo "Required 'BACKUP_PATH' env not set" && exit 1;
[[ -z "${JENKINS_HOME}" ]] && echo "Required 'JENKINS_HOME' env not set" && exit 1;
backup_number=$1
echo "Running backup #${backup_number}"
BACKUP_TMP_DIR=$(mktemp -d)
tar -C ${JENKINS_HOME} -czf "${BACKUP_TMP_DIR}/${backup_number}.tar.gz" --exclude jobs/*/workspace* -c jobs && \
aws s3 cp ${BACKUP_TMP_DIR}/${backup_number}.tar.gz s3://${BACKUP_BUCKET}/${BACKUP_PATH}/${backup_number}.tar.gz
echo Done
restore.sh: |-
#!/bin/bash -xeu
[[ ! $# -eq 1 ]] && echo "Usage: $0 backup_number" && exit 1
[[ -z "${BACKUP_BUCKET}" ]] && echo "Required 'BACKUP_BUCKET' env not set" && exit 1;
[[ -z "${BACKUP_PATH}" ]] && echo "Required 'BACKUP_PATH' env not set" && exit 1;
[[ -z "${JENKINS_HOME}" ]] && echo "Required 'JENKINS_HOME' env not set" && exit 1;
backup_number=$1
echo "Running restore #${backup_number}"
BACKUP_TMP_DIR=$(mktemp -d)
aws s3 cp s3://${BACKUP_BUCKET}/${BACKUP_PATH}/${backup_number}.tar.gz ${BACKUP_TMP_DIR}/${backup_number}.tar.gz
tar -C ${JENKINS_HOME} -zxf "${BACKUP_TMP_DIR}/${backup_number}.tar.gz"
echo Done
```
In our example we will use S3 bucket lifecycle policy to keep
the number of backups under control, e.g. Cloud Formation fragment:
```yaml
Type: AWS::S3::Bucket
Properties:
BucketName: my-example-bucket
...
LifecycleConfiguration:
Rules:
- Id: BackupCleanup
Status: Enabled
Prefix: my-backup-path
ExpirationInDays: 7
NoncurrentVersionExpirationInDays: 14
AbortIncompleteMultipartUpload:
DaysAfterInitiation: 3
```

View File

@ -0,0 +1,203 @@
---
title: "Customizing Jenkins"
linkTitle: "Customizing Jenkins"
weight: 3
date: 2021-12-08
description: >
How to customize Jenkins
---
## How to customize Jenkins
Jenkins can be customized with plugins.
Plugin's configuration is applied as groovy scripts or the [configuration as code plugin](https://github.com/jenkinsci/configuration-as-code-plugin).
Any plugin working for Jenkins can be installed by the Jenkins Operator.
Pre-installed plugins:
* configuration-as-code v1.55
* git v4.10.0
* job-dsl v1.78.1
* kubernetes-credentials-provider v0.20
* kubernetes v1.30.11
* workflow-aggregator v2.6
* workflow-job v2.42
Rest of the plugins can be found in [plugins repository](https://plugins.jenkins.io/).
#### Install plugins
Edit Custom Resource under `spec.master.plugins`:
```yaml
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
spec:
master:
plugins:
- name: simple-theme-plugin
version: "0.7"
```
Under `spec.master.basePlugins` you can find plugins for a valid **Jenkins Operator**:
```yaml
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
spec:
master:
basePlugins:
- name: kubernetes
version: "1.30.11"
- name: workflow-job
version: "2.42"
- name: workflow-aggregator
version: "2.6"
- name: git
version: "4.10.0"
- name: job-dsl
version: "1.78.1"
- name: configuration-as-code
version: "1.55"
- name: kubernetes-credentials-provider
version: "0.20"
```
You can change their versions.
The **Jenkins Operator** will then automatically install plugins after the Jenkins master pod restart.
#### Apply plugin's config
By using a [ConfigMap](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/) you can create your own **Jenkins** customized configuration.
Then you must reference the **`ConfigMap`** in the **Jenkins** pod customization file in `spec.groovyScripts` or `spec.configurationAsCode`
Create a **`ConfigMap`** with specific name (eg. `jenkins-operator-user-configuration`). Then, modify the **Jenkins** manifest:
```yaml
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
spec:
configurationAsCode:
configurations:
- name: jenkins-operator-user-configuration
groovyScripts:
configurations:
- name: jenkins-operator-user-configuration
```
Here is an example of `jenkins-operator-user-configuration`:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: jenkins-operator-user-configuration
data:
1-configure-theme.groovy: |
import jenkins.*
import jenkins.model.*
import hudson.*
import hudson.model.*
import org.jenkinsci.plugins.simpletheme.ThemeElement
import org.jenkinsci.plugins.simpletheme.CssTextThemeElement
import org.jenkinsci.plugins.simpletheme.CssUrlThemeElement
Jenkins jenkins = Jenkins.getInstance()
def decorator = Jenkins.instance.getDescriptorByType(org.codefirst.SimpleThemeDecorator.class)
List<ThemeElement> configElements = new ArrayList<>();
configElements.add(new CssTextThemeElement("DEFAULT"));
configElements.add(new CssUrlThemeElement("https://cdn.rawgit.com/afonsof/jenkins-material-theme/gh-pages/dist/material-light-green.css"));
decorator.setElements(configElements);
decorator.save();
jenkins.save()
1-system-message.yaml: |
jenkins:
systemMessage: "Configuration as Code integration works!!!"
```
* `*.groovy` is Groovy script configuration
* `*.yaml is` configuration as code
If you want to correct your configuration you can edit it while the **Jenkins Operator** is running.
Jenkins will reconcile and apply the new configuration.
## How to use secrets from a Groovy scripts
If you configured `spec.groovyScripts.secret.name`, then this secret is available to use from map Groovy scripts.
The secrets are loaded to `secrets` map.
Create a [secret](https://kubernetes.io/docs/concepts/configuration/secret/) with for example the name `jenkins-conf-secrets`.
```yaml
kind: Secret
apiVersion: v1
type: Opaque
metadata:
name: jenkins-conf-secrets
namespace: default
data:
SYSTEM_MESSAGE: SGVsbG8gd29ybGQ=
```
Then modify the **Jenkins** pod manifest by changing `spec.groovyScripts.secret.name` to `jenkins-conf-secrets`.
```yaml
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
spec:
configurationAsCode:
configurations:
- name: jenkins-operator-user-configuration
secret:
name: jenkins-conf-secrets
groovyScripts:
configurations:
- name: jenkins-operator-user-configuration
secret:
name: jenkins-conf-secrets
```
Now you can test that the secret is mounted by applying this `ConfigMap` for Groovy script:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: jenkins-operator-user-configuration
data:
1-system-message.groovy: |
import jenkins.*
import jenkins.model.*
import hudson.*
import hudson.model.*
Jenkins jenkins = Jenkins.getInstance()
jenkins.setSystemMessage(secrets["SYSTEM_MESSAGE"])
jenkins.save()
```
Or by applying this configuration as code:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: jenkins-operator-user-configuration
data:
1-system-message.yaml: |
jenkins:
systemMessage: ${SYSTEM_MESSAGE}
```
After this, you should see the `Hello world` system message from the **Jenkins** homepage.

View File

@ -0,0 +1,114 @@
---
title: "Deploying Jenkins"
linkTitle: "Deploying Jenkins"
weight: 2
date: 2021-12-08
description: >
Deploy production ready Jenkins manifest
---
{{% pageinfo %}}
This document describes the procedure for deploying Jenkins.
{{% /pageinfo %}}
## Prerequisites
The Operator needs to have been deployed beforehand. The procedure for deploying Jenkins described here doesn't apply to
installation of Operator via Helm chart unless `jenkins.enabled` was set to false.
Thats because by default, installation via Helm chart also covers deploying Jenkins.
## Deploying Jenkins instance
Once Jenkins Operator is up and running let's deploy actual Jenkins instance.
Create manifest e.g. **`jenkins_instance.yaml`** with following data and save it on drive.
```yaml
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
namespace: default
spec:
configurationAsCode:
configurations: []
secret:
name: ""
groovyScripts:
configurations: []
secret:
name: ""
jenkinsAPISettings:
authorizationStrategy: createUser
master:
disableCSRFProtection: false
containers:
- name: jenkins-master
image: jenkins/jenkins:2.319.1-lts-alpine
imagePullPolicy: Always
livenessProbe:
failureThreshold: 12
httpGet:
path: /login
port: http
scheme: HTTP
initialDelaySeconds: 100
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
readinessProbe:
failureThreshold: 10
httpGet:
path: /login
port: http
scheme: HTTP
initialDelaySeconds: 80
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
limits:
cpu: 1500m
memory: 3Gi
requests:
cpu: "1"
memory: 500Mi
seedJobs:
- id: jenkins-operator
targets: "cicd/jobs/*.jenkins"
description: "Jenkins Operator repository"
repositoryBranch: master
repositoryUrl: https://github.com/jenkinsci/kubernetes-operator.git
```
Deploy a Jenkins to Kubernetes:
```bash
kubectl create -f jenkins_instance.yaml
```
Watch the Jenkins instance being created:
```bash
kubectl get pods -w
```
Get the Jenkins credentials:
```bash
kubectl get secret jenkins-operator-credentials-<cr_name> -o 'jsonpath={.data.user}' | base64 -d
kubectl get secret jenkins-operator-credentials-<cr_name> -o 'jsonpath={.data.password}' | base64 -d
```
Connect to the Jenkins instance (minikube):
```bash
minikube service jenkins-operator-http-<cr_name> --url
```
Connect to the Jenkins instance (actual Kubernetes cluster):
```bash
kubectl port-forward jenkins-<cr_name> 8080:8080
```
Then open browser with address `http://localhost:8080`.
![jenkins](/kubernetes-operator/img/jenkins.png)

View File

@ -0,0 +1,988 @@
---
title: "Installing the Operator"
linkTitle: "Installing the Operator"
weight: 1
date: 2023-01-08
description: >
How to install Jenkins Operator
---
{{% pageinfo %}}
This document describes installation procedure for **Jenkins Operator**.
All container images can be found at [virtuslab/jenkins-operator](https://hub.docker.com/r/virtuslab/jenkins-operator) Docker Hub repository.
{{% /pageinfo %}}
## Requirements
To run **Jenkins Operator**, you will need:
- access to a Kubernetes cluster version `1.17+`
- `kubectl` version `1.17+`
Listed below are the two ways to deploy Jenkins Operator.
## Deploy Jenkins Operator using YAML's
First, install Jenkins Custom Resource Definition:
```bash
kubectl apply -f https://raw.githubusercontent.com/jenkinsci/kubernetes-operator/master/config/crd/bases/jenkins.io_jenkins.yaml
```
Then, install the Operator and other required resources:
```bash
kubectl apply -f https://raw.githubusercontent.com/jenkinsci/kubernetes-operator/master/deploy/all-in-one-v1alpha2.yaml
```
Watch **Jenkins Operator** instance being created:
```bash
kubectl get pods -w
```
Now **Jenkins Operator** should be up and running in the `default` namespace.
For deploying Jenkins, refer to [Deploy Jenkins section](/kubernetes-operator/docs/getting-started/latest/deploying-jenkins/).
## Deploy Jenkins Operator using Helm Chart
Alternatively, you can also use Helm to install the Operator (and optionally, by default, Jenkins). It requires the Helm 3+ for deployment.
Create a namespace for the operator:
```bash
$ kubectl create namespace <your-namespace>
```
To install, you need only to type these commands:
```bash
$ helm repo add jenkins https://raw.githubusercontent.com/jenkinsci/kubernetes-operator/master/chart
$ helm install <name> jenkins/jenkins-operator -n <your-namespace>
```
To add custom labels and annotations, you can use `values.yaml` file or pass them into `helm install` command, e.g.:
```bash
$ helm install <name> jenkins/jenkins-operator -n <your-namespace> --set jenkins.labels.LabelKey=LabelValue,jenkins.annotations.AnnotationKey=AnnotationValue
```
You can further customize Jenkins using `values.yaml`:
<h3 id="JenkinsConfiguration">Jenkins instance configuration
</h3>
<table aria-colspan="4">
<thead aria-colspan="4">
<tr>
<th></th>
<th>Field</th>
<th>Default value</th>
<th>Description</th>
</tr>
</thead>
<tbody aria-colspan="4">
<tr></tr>
<tr>
<td colspan="1">
<code>jenkins</code>
</td>
<td colspan="3">
<p>operator is section for configuring operator deployment</p>
<table>
<tr>
<td>
<code>enabled</code>
</td>
<td>
true
</td>
<td>
Enabled can enable or disable the Jenkins instance.
Set to false if you have configured CR already and/or you want to deploy an operator only.
</td>
</tr>
<tr>
<td>
<code>apiVersion</code>
</td>
<td>jenkins.io/v1alpha2</td>
<td>
Version of the CR manifest. The recommended and default value is <code>jenkins.io/v1alpha2</code>.
<a href="#github.io/kubernetes-operator/docs/getting-started/v0.1.x/migration-guide-v1alpha1-to-v1alpha2/">More info</a>
</td>
</tr>
<tr>
<td>
<code>name</code>
</td>
<td>
jenkins
</td>
<td>
Name of resource. The pod name will be <code>jenkins-&lt;name&gt;</code> (name will be set as suffix).
</td>
</tr>
<tr>
<td>
<code>namespace</code>
</td>
<td>
default
</td>
<td>
Namespace the resources will be deployed to. It's not recommended to use default namespace.
Create new namespace for jenkins (e.g. <code>kubectl create -n jenkins</code>)
</td>
</tr>
<tr>
<td>
<code>labels</code>
</td>
<td>
{}
</td>
<td>
Labels are injected into metadata labels field.
</td>
</tr>
<tr>
<td>
<code>annotations</code>
</td>
<td>
{}
</td>
<td>
Annotations are injected into metadata annotations field.
</td>
</tr>
<tr>
<td>
<code>image</code>
</td>
<td>
jenkins/jenkins:lts
</td>
<td>
Image is the name (and tag) of the Jenkins instance.
It's recommended to use LTS (tag: "lts") version.
</td>
</tr>
<tr>
<td>
<code>env</code>
</td>
<td>
[]
</td>
<td>
Env contains jenkins container environment variables.
</td>
</tr>
<tr>
<td>
<code>imagePullPolicy</code>
</td>
<td>
Always
</td>
<td>
Defines policy for pulling images
</td>
</tr>
<tr>
<td>
<code>priorityClassName</code>
</td>
<td>
""
</td>
<td>
PriorityClassName indicates the importance of a Pod relative to other Pods.
<a href="https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/">More info</a>
</td>
</tr>
<tr>
<td>
<code>disableCSRFProtection</code>
</td>
<td>
false
</td>
<td>
disableCSRFProtection can enable or disable operator built-in CSRF protection.
Set it to true if you are using OpenShift Jenkins Plugin.
<a href="https://github.com/jenkinsci/kubernetes-operator/pull/193">More info</a>
</td>
</tr>
<tr>
<td>
<code>imagePullSecrets</code>
</td>
<td>
[]
</td>
<td>
Used if you want to pull images from private repository
<a href="https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/configuration/#pulling-docker-images-from-private-repositories">More info</a>
</td>
</tr>
<tr>
<td>
<code>notifications</code>
</td>
<td>
[]
</td>
<td>
Notifications is feature that notify user about Jenkins reconciliation status
<a href="https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/notifications/">More info</a>
</td>
</tr>
<tr>
<td>
<code>basePlugins</code>
</td>
<td>
<pre>
- name: kubernetes
version: "1.25.2"
- name: workflow-job
version: "2.39"
- name: workflow-aggregator
version: "2.6"
- name: git
version: "4.2.2"
- name: job-dsl
version: "1.77"
- name: configuration-as-code
version: "1.38"
- name: kubernetes-credentials
-provider
version: "0.13"
</pre>
</td>
<td>
Plugins installed and required by the operator
shouldn't contain plugins defined by user
You can change their versions here
<a href="https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/customization/#install-plugins">More info</a>
</td>
</tr>
<tr>
<td>
<code>plugins</code>
</td>
<td>
[]
</td>
<td>
Plugins required by the user. You can define plugins here.
<a href="https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/customization/#install-plugins">More info</a>
Example:
<pre>
plugins:
- name: simple-theme-plugin
version: 0.5.1
</pre>
</td>
</tr>
<tr>
<td>
<code>seedJobs</code>
</td>
<td>
[]
</td>
<td>
Placeholder for jenkins seed jobs
For seed job creation tutorial, check:<br /> <a href="https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/configuring-seed-jobs-and-pipelines/#prepare-job-definitions-and-pipelines">Prepare seed jobs</a>
<br /><a href="https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/configuring-seed-jobs-and-pipelines/#configure-seed-jobs">Configure seed jobs</a>
<br />Example:
<code>
<pre>
seedJobs:
- id: jenkins-operator
targets: "cicd/jobs/*.jenkins"
description: "Jenkins Operator repository"
repositoryBranch: master
repositoryUrl:
- https://github.com/jenkinsci/kubernetes-operator.git
</pre>
</code>
</td>
</tr>
<tr>
<td>
<code>resources</code>
</td>
<td>
<pre>
limits:
cpu: 1500m
memory: 3Gi
requests:
cpu: 1
memory: 500M
</pre>
</td>
<td>
Resource limit/request for Jenkins
<a href="https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container">More info</a>
</td>
</tr>
<tr>
<td>
<code>volumes</code>
</td>
<td>
<pre>
- name: backup
persistentVolumeClaim:
claimName: jenkins-backup
</pre>
</td>
<td>
Volumes used by Jenkins
By default, we are only using PVC volume for storing backups.
</td>
</tr>
<tr>
<td>
<code>volumeMounts</code>
</td>
<td>
[]
</td>
<td>
volumeMounts are mounts for Jenkins pod.
</td>
</tr>
<tr>
<td>
<code>securityContext</code>
</td>
<td>
runAsUser: 1000
fsGroup: 1000
</td>
<td>
SecurityContext for pod.
</td>
</tr>
<tr>
<td><code>service</code></td>
<td>not implemented</td>
<td>Http Jenkins service. See https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/schema/#github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2.Service for details.</td>
</tr>
<tr>
<td><code>slaveService</code></td>
<td>not implemented</td>
<td>Slave Jenkins service. See https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/schema/#github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2.Service for details.</td>
</tr>
<tr>
<td>
<code>livenessProbe</code>
</td>
<td>
<pre>
livenessProbe:
failureThreshold: 12
httpGet:
path: /login
port: http
scheme: HTTP
initialDelaySeconds: 80
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
</pre>
</td>
<td>
livenessProbe for Pod
</td>
</tr>
<tr>
<td>
<code>readinessProbe</code>
</td>
<td>
<pre>
readinessProbe:
failureThreshold: 3
httpGet:
path: /login
port: http
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
</pre>
</td>
<td>
readinessProbe for Pod
</td>
</tr>
<tr>
<td>
<code>
backup
</code>
<p>
<em>
<a href="#Backup">
Backup
</a>
</em>
</p>
</td>
<td>
</td>
<td>
Backup is section for configuring operator's backup feature
By default backup feature is enabled and pre-configured
This section simplifies the configuration described here: <a href="https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/configuring-backup-and-restore/">Configuring backup and restore</a>
For customization tips see <a href="https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/custom-backup-and-restore">Custom backup and restore</a>
</td>
</tr>
<tr>
<td>
<code>configuration</code>
<p>
<em>
<a href="#Configuration">
Configuration
</a>
</em>
</p>
</td>
<td></td>
<td>
Section where we can configure Jenkins instance.
See <a href="https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/customizing-jenkins/">Customizing Jenkins</a> for details
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
### Configuring operator deployment
<table aria-colspan="4">
<thead aria-colspan="4">
<tr>
<th></th>
<th>Field</th>
<th>Default value</th>
<th>Description</th>
</tr>
</thead>
<tbody aria-colspan="4">
<tr></tr>
<tr>
<td colspan="1">
<code>operator</code>
</td>
<td colspan="3">
<p>operator is section for configuring operator deployment</p>
<table>
<tr>
<td>
<code>replicaCount</code></br>
</td>
<td>
1
</td>
<td>
Number of Replicas.
</td>
</tr>
<tr>
<td>
<code>image</code>
</td>
<td>
virtuslab/jenkins-operator:v0.4.0
</td>
<td>
Name (and tag) of the Jenkins Operator image.
</td>
</tr>
<tr>
<td>
<code>imagePullPolicy</code>
</td>
<td>
IfNotPresent
</td>
<td>
Defines policy for pulling images.
</td>
</tr>
<tr>
<td>
<code>imagePullSecrets</code>
</td>
<td>
[]
</td>
<td>
Used if you want to pull images from private repository.
</td>
</tr>
<tr>
<td>
<code>nameOverride</code>
</td>
<td>
""
</td>
<td>
nameOverride overrides the app name.
</td>
</tr>
<tr>
<td>
<code>fullnameOverride</code>
</td>
<td>
""
</td>
<td>
fullnameOverride overrides the deployment name
</td>
</tr>
<tr>
<td>
<code>resources</code>
</td>
<td>
{}
</td>
<td>
</td>
</tr>
<tr>
<td>
<code>nodeSelector</code>
</td>
<td>
{}
</td>
<td>
</td>
</tr>
<tr>
<td>
<code>tolerations</code>
</td>
<td>
{}
</td>
<td>
</td>
</tr>
<tr>
<td>
<code>affinity</code>
</td>
<td>
{}
</td>
<td>
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
<h3 id="Backup">Backup
</h3>
<p>
(<em>Appears on:</em>
<a href="#JenkinsConfiguration">JenkinsConfiguration</a>)
</p>
<p>
Backup defines configuration of Jenkins backup.
</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Default value</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>enabled</code>
</td>
<td>
true
</td>
<td>
Enabled is enable/disable switch for backup feature.
</td>
</tr>
<tr>
<td>
<code>image</code>
</td>
<td>
virtuslab/jenkins-operator-backup-pvc:v0.1.1
</td>
<td>
Image used by backup feature.
</td>
</tr>
<tr>
<td>
<code>containerName</code>
</td>
<td>
backup
</td>
<td>
Backup container name.
</td>
</tr>
<tr>
<td>
<code>interval</code>
</td>
<td>
30
</td>
<td>
Defines how often make backup in seconds.
</td>
</tr>
<tr>
<td>
<code>makeBackupBeforePodDeletion</code>
</td>
<td>
true
</td>
<td>
When enabled will make backup before pod deletion.
</td>
</tr>
<tr>
<td>
<code>backupCommand</code>
</td>
<td>
/home/user/bin/backup.sh
</td>
<td>
Backup container command.
</td>
</tr>
<tr>
<td>
<code>restoreCommand</code>
</td>
<td>
/home/user/bin/restore.sh
</td>
<td>
Backup restore command.
</td>
</tr>
<tr>
<td>
<code>pvc</code>
</td>
<td colspan="2">
<p>Persistent Volume Claim Kubernetes resource</p>
<br/>
<table colspan="2" style="width:100%">
<tbody>
<tr>
<td>
<code>enabled</code>
</td>
<td>
true
</td>
<td>
Enable/disable switch for PVC
</td>
</tr>
<tr>
<td>
<code>enabled</code>
</td>
<td>
true
</td>
<td>
Enable/disable switch for PVC
</td>
</tr>
<tr>
<td>
<code>size</code>
</td>
<td>
5Gi
</td>
<td>
Size of PVC
</td>
</tr>
<tr>
<td>
<code>className</code>
</td>
<td>
""
</td>
<td>
StorageClassName for PVC
<a href="https://kubernetes.io/docs/concepts/storage/persistent-volumes/#class-1">More info</a>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>
<code>env</code>
</td>
<td>
<pre>
- name: BACKUP_DIR
value: /backup
- name: JENKINS_HOME
value: /jenkins-home
- name: BACKUP_COUNT
value: "3"
</pre>
</td>
<td>
Contains container environment variables.
PVC backup provider handles these variables:<br />
BACKUP_DIR - path for storing backup files (default: "/backup")<br />
JENKINS_HOME - path to jenkins home (default: "/jenkins-home")<br />
BACKUP_COUNT - define how much recent backups will be kept<br />
</td>
</td>
</tr>
<tr>
<td>
<code>volumeMounts</code>
</td>
<td>
<pre>
- name: jenkins-home
mountPath: /jenkins-home
- mountPath: /backup
name: backup
</pre>
</td>
<td>
Holds the mount points for volumes.
</td>
</tr>
</tbody>
</table>
<h4 id="Configuration">Configuration
</h3>
<p>
(<em>Appears on:</em>
<a href="#JenkinsConfiguration">Jenkins instance configuration</a>)
</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Default value</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>configurationAsCode</code>
</td>
<td>
{}
</td>
<td>
ConfigurationAsCode defines configuration of Jenkins customization via Configuration as Code Jenkins plugin.
Example:<br />
<pre>
- configMapName: jenkins-casc
content: {}
</pre>
</td>
</tr>
<tr>
<td>
<code>groovyScripts</code>
</td>
<td>
{}
</td>
<td>
GroovyScripts defines configuration of Jenkins customization via groovy scripts.
Example:<br />
<pre>
- configMapName: jenkins-gs
content: {}
</pre>
</td>
</tr>
<tr>
<td>
<code>secretRefName</code>
</td>
<td>
""
</td>
<td>
secretRefName of existing secret (previously created).
</td>
</tr>
<tr>
<td>
<code>secretData</code>
</td>
<td>
{}
</td>
<td>
If secretRefName is empty, secretData creates new secret and fills with data provided in secretData.
</td>
</tr>
</tbody>
</table>
## Note on Operator's nightly built images
If you wish to use the newest, not yet released version of the Operator, you can use one of nightly built snapshot images, however the maintainers of this project cannot guarantee their stability.
You can find nightly built images by heading to [virtuslab/jenkins-operator](https://hub.docker.com/r/virtuslab/jenkins-operator) Docker Hub repository and looking for images with tag in the form of `{git-hash}`, {git-hash} being the hash of master branch commit that you want to use snapshot of.
## Note on restricted Jenkins controller pod volumeMounts
Current design of the Operator puts an emphasis on creating a full GitOps flow of work for Jenkins users.
One of the key points of this design is maintaining an immutable state of Jenkins.
One of the prerequisites of this is an ephemeral Jenkins home directory. To achieve that, Operator mounts emptyDir Volume
(jenkins-home) as Jenkins home directory.
It is not possible to overwrite volumeMount and specify any other Volume for Jenkins home directory,
as attempting to do so will result in Operator error.
jenkins-home is not the only Jenkins controller pod volumeMount that is non-configurable and managed by Operator,
below is the full list of those volumeMounts:
* jenkins-home
* scripts
* init-configuration
* operator-credentials
## Validating Webhook
Validating webhook can be used in order to increase the Operator's capabilities to monitor security issues. It will look for security vulnerabilities in the base and requested plugins. It can be easily installed via Helm charts by setting webhook.enabled in values.yaml.
**Note**: The webhook takes some time to get up and running. It's recommended to first deploy the Operator and later Jenkins Custom Resource by using toggles in `values.yaml`.
For the installation with yaml manifests (without using Helm chart), first, install cert-manager:
```bash
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.5.1/cert-manager.yaml
```
It takes some time to get cert-manager up and running.
Then, install the webhook and other required resources:
```bash
kubectl apply -f https://raw.githubusercontent.com/jenkinsci/kubernetes-operator/master/deploy/all-in-one-webhook.yaml
```
Now, download the manifests for the operator and other resources from [here](https://raw.githubusercontent.com/jenkinsci/kubernetes-operator/master/deploy/all-in-one-v1alpha2.yaml) and provide these additional fields in the Operator manifest:
<pre>
<code>
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins-operator
labels:
control-plane: controller-manager
spec:
selector:
matchLabels:
control-plane: controller-manager
replicas: 1
template:
metadata:
labels:
control-plane: controller-manager
spec:
serviceAccountName: jenkins-operator
securityContext:
runAsUser: 65532
containers:
- command:
- /manager
args:
- --leader-elect
<b>- --validate-security-warnings</b>
image: virtuslab/jenkins-operator:v0.7.0
name: jenkins-operator
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false
livenessProbe:
httpGet:
path: /healthz
port: 8081
initialDelaySeconds: 15
periodSeconds: 20
readinessProbe:
httpGet:
path: /readyz
port: 8081
initialDelaySeconds: 5
periodSeconds: 10
resources:
limits:
cpu: 200m
memory: 100Mi
requests:
cpu: 100m
memory: 20Mi
env:
- name: WATCH_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
<b>volumeMounts:
- mountPath: /tmp/k8s-webhook-server/serving-certs
name: webhook-certs
readOnly: true
volumes:
- name: webhook-certs
secret:
defaultMode: 420
secretName: jenkins-webhook-certificate
terminationGracePeriodSeconds: 10</b>
</code>
</pre>
To enable security validation in the Jenkins Custom Resource, set
>jenkins.ValidateSecurityWarnings=true

View File

@ -0,0 +1,127 @@
---
title: "LDAP"
linkTitle: "LDAP"
weight: 9
date: 2021-12-08
description: >
Additional configuration for LDAP
---
Configuring LDAP is not supported out of the box, but can be achieved through
plugins and some well tuned configurations.
The plugin we will use is: <https://plugins.jenkins.io/ldap/>
> Note: This is an example of how LDAP authentication can be achieved. The LDAP
> plugin is from a third-party, and there may be other alternatives that suits
> your use case better. Use this guide with a grain of salt.
## Requirements
- LDAP server accessible from the Kubernetes cluster where your Jenkins
instance will live.
- Credentials to a manager account in your AD. Jenkins Operator will use
this account to authenticate with Jenkins for health checks, seed jobs, etc.
## Steps
In your Jenkins configuration, add the following plugin:
```yaml
plugins:
# Check https://plugins.jenkins.io/ldap/ to find the latest version.
- name: ldap
version: "2.7"
```
Easiest step is to then start up Jenkins then navigate to your instance's
"Configure Global Security" page and configure it accordingly.
`http://jenkins.example.com/configureSecurity/`
Once it's set up and tested, you can navigate to your JCasC page and export
the LDAP settings.
`https://jenkins.example.com/configuration-as-code/`
Feed the relevant new settings into your Kubernetes ConfigMap for your JCasC
settings.
Here's a snippet of the LDAP-related configurations:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: jenkins-casc
data:
ldap.yaml: |
jenkins:
securityRealm:
ldap:
configurations:
- displayNameAttributeName: "name"
groupSearchBase: "OU=Groups,OU=MyCompany"
groupSearchFilter: "(& (cn={0}) (objectclass=group) )"
inhibitInferRootDN: false
managerDN: "CN=Jenkins Admin,OU=UsersSystem,OU=UsersOther,OU=MyCompany,DC=mycompany,DC=local"
managerPasswordSecret: "${LDAP_MANAGER_PASSWORD}"
rootDN: "DC=mycompany,DC=local"
server: "MyCompany.local"
userSearch: "SamAccountName={0}"
userSearchBase: "OU=MyCompany"
disableMailAddressResolver: false
disableRolePrefixing: true
groupIdStrategy: "caseInsensitive"
userIdStrategy: "caseInsensitive"
```
> Note the use of `${LDAP_MANAGER_PASSWORD}` above. You can reference
> Kubernetes secrets in your JCasC ConfigMaps by adding the following to your
> Jenkins object:
>
> ```yaml
> kind: Jenkins
> spec:
> configurationAsCode:
> configurations:
> - name: jenkins-casc
> secret:
> # This here
> name: jenkins-casc-secrets
> ```
>
> ```yaml
> apiVersion: v1
> kind: Secret
> metadata:
> name: jenkins-cred-conf-secrets
> stringData:
> LDAP_MANAGER_PASSWORD: <password-for-manager-created-in-ldap>
> ```
>
> Schema reference: [v1alpha2.ConfigurationAsCode](./schema/#github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkins/v1alpha2.ConfigurationAsCode)
Finally you must configure the Jenkins operator to use the manager's
credentials from the AD.
This is because this procedure will disable Jenkins' own user database, and the
Jenkins operator still needs to be able to talk to Jenkins in an authorized
manner.
Create the following Kubernetes secret:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: jenkins-operator-credentials-<jenkins-cr-name>
namespace: <jenkins-cr-namespace>
stringData:
user: <username-for-manager-created-in-ldap>
password: <password-for-manager-created-in-ldap>
```
> Note: Values in stringData do not need to be base64 encoded. They are
> encoded by Kubernetes when the manifest is applied.

View File

@ -0,0 +1,10 @@
---
title: "OpenShift"
linkTitle: "OpenShift"
weight: 10
date: 2021-12-08
description: >
Additional configuration for OpenShift
---
## Release 0.7.0 is not compatible with OpenShift.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,583 @@
---
title: "Separate namespaces for Jenkins and Operator"
linkTitle: "Separate namespaces for Jenkins and Operator"
weight: 6
date: 2021-12-08
description: >
How to install Jenkins and Jenkins Operator in separate namespaces
---
## Create namespaces
You need to create two namespaces, for example we'll call them **jenkins** for Jenkins and **jenkins-operator** for Jenkins Operator.
```bash
$ kubectl create ns jenkins-operator
$ kubectl create ns jenkins
```
## Create necessary resources in Jenkins Operator namespace
Next, you need to install resources necessary for the Operator to work in the `jenkins-operator` namespace. To do that,
copy the manifest you see below to `jenkins-operator-rbac.yaml`file.
```yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins-operator
---
# permissions to do leader election.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: leader-election-role
rules:
- apiGroups:
- ""
- coordination.k8s.io
resources:
- configmaps
- leases
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: leader-election-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: leader-election-role
subjects:
- kind: ServiceAccount
name: jenkins-operator
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: jenkins-operator
rules:
- apiGroups:
- apps
resources:
- daemonsets
- deployments
- replicasets
- statefulsets
verbs:
- '*'
- apiGroups:
- apps
- jenkins-operator
resources:
- deployments/finalizers
verbs:
- update
- apiGroups:
- build.openshift.io
resources:
- buildconfigs
- builds
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- configmaps
- secrets
- services
verbs:
- create
- get
- list
- update
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- get
- list
- patch
- watch
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- pods
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- ""
resources:
- pods
- pods/exec
verbs:
- '*'
- apiGroups:
- ""
resources:
- pods/log
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- pods/portforward
verbs:
- create
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- create
- get
- list
- update
- watch
- apiGroups:
- image.openshift.io
resources:
- imagestreams
verbs:
- get
- list
- watch
- apiGroups:
- jenkins.io
resources:
- '*'
verbs:
- '*'
- apiGroups:
- jenkins.io
resources:
- jenkins
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- jenkins.io
resources:
- jenkins/finalizers
verbs:
- update
- apiGroups:
- jenkins.io
resources:
- jenkins/status
verbs:
- get
- patch
- update
- apiGroups:
- rbac.authorization.k8s.io
resources:
- rolebindings
- roles
verbs:
- create
- get
- list
- update
- watch
- apiGroups:
- route.openshift.io
resources:
- routes
verbs:
- create
- get
- list
- update
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: jenkins-operator
subjects:
- kind: ServiceAccount
name: jenkins-operator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: jenkins-operator
```
Now install the required resources in `jenkins-operator` namespace with:
```bash
kubectl apply -n jenkins-operator -f jenkins-operator-rbac.yaml
```
There's only one thing left to install in `jenkins-operator` namespace, and that is the Operator itself. The manifest
below contains the Operator as defined in all-in-one manifest found in [Installing the Operator](/kubernetes-operator/docs/getting-started/latest/installing-the-operator/)
page, the only difference is that the one here sets `WATCH_NAMESPACE` to the `jenkins` namespace we created.
Copy its content to `jenkins-operator.yaml` file.
```bash
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins-operator
labels:
control-plane: controller-manager
spec:
selector:
matchLabels:
control-plane: controller-manager
replicas: 1
template:
metadata:
labels:
control-plane: controller-manager
spec:
serviceAccountName: jenkins-operator
securityContext:
runAsUser: 65532
containers:
- command:
- /manager
args:
- --leader-elect
image: virtuslab/jenkins-operator:v0.7.0
name: jenkins-operator
imagePullPolicy: IfNotPresent
securityContext:
allowPrivilegeEscalation: false
livenessProbe:
httpGet:
path: /healthz
port: 8081
initialDelaySeconds: 15
periodSeconds: 20
readinessProbe:
httpGet:
path: /readyz
port: 8081
initialDelaySeconds: 5
periodSeconds: 10
resources:
limits:
cpu: 100m
memory: 30Mi
requests:
cpu: 100m
memory: 20Mi
env:
- name: WATCH_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
terminationGracePeriodSeconds: 10
```
Install the Operator in `jenkins-operator` namespace with:
```bash
kubectl apply -n jenkins-operator -f jenkins-operator.yaml
```
You have installed the Operator in `jenkins-operator` namespace, watching for Jenkins in `jenkins` namespace. Now
there are two things left to do: creating necessary Role and RoleBinding for the Operator in `jenkins` namespace, and
deploying actual Jenkins instance there.
## Create necessary resources in Jenkins namespace
Below you can find manifest with RBAC that needs to be created in `jenkins` namespace. Copy its content to `jenkins-ns-rbac.yaml` file.
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: jenkins-operator
rules:
- apiGroups:
- apps
resources:
- daemonsets
- deployments
- replicasets
- statefulsets
verbs:
- '*'
- apiGroups:
- apps
- jenkins-operator
resources:
- deployments/finalizers
verbs:
- update
- apiGroups:
- build.openshift.io
resources:
- buildconfigs
- builds
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- configmaps
- secrets
- services
verbs:
- create
- get
- list
- update
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- get
- list
- patch
- watch
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- pods
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- ""
resources:
- pods
- pods/exec
verbs:
- '*'
- apiGroups:
- ""
resources:
- pods/log
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- pods/portforward
verbs:
- create
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- create
- get
- list
- update
- watch
- apiGroups:
- image.openshift.io
resources:
- imagestreams
verbs:
- get
- list
- watch
- apiGroups:
- jenkins.io
resources:
- '*'
verbs:
- '*'
- apiGroups:
- jenkins.io
resources:
- jenkins
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- jenkins.io
resources:
- jenkins/finalizers
verbs:
- update
- apiGroups:
- jenkins.io
resources:
- jenkins/status
verbs:
- get
- patch
- update
- apiGroups:
- rbac.authorization.k8s.io
resources:
- rolebindings
- roles
verbs:
- create
- get
- list
- update
- watch
- apiGroups:
- route.openshift.io
resources:
- routes
verbs:
- create
- get
- list
- update
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: jenkins-operator
subjects:
- kind: ServiceAccount
name: jenkins-operator
namespace: jenkins-operator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: jenkins-operator
```
Now apply it with:
```bash
kubectl apply -n jenkins -f jenkins-ns-rbac.yaml
```
The last thing to do is to deploy Jenkins. Below you can find an example Jenkins resource manifest.
It's the same as one used in [Deploying Jenkins](/kubernetes-operator/docs/getting-started/latest/deploying-jenkins/).
Copy it to `jenkins-instance.yaml`
```yaml
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
spec:
configurationAsCode:
configurations: []
secret:
name: ""
groovyScripts:
configurations: []
secret:
name: ""
jenkinsAPISettings:
authorizationStrategy: createUser
master:
disableCSRFProtection: false
containers:
- name: jenkins-master
image: jenkins/jenkins:2.319.1-lts-alpine
imagePullPolicy: Always
livenessProbe:
failureThreshold: 12
httpGet:
path: /login
port: http
scheme: HTTP
initialDelaySeconds: 100
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
readinessProbe:
failureThreshold: 10
httpGet:
path: /login
port: http
scheme: HTTP
initialDelaySeconds: 80
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
limits:
cpu: 1500m
memory: 3Gi
requests:
cpu: "1"
memory: 500Mi
seedJobs:
- id: jenkins-operator
targets: "cicd/jobs/*.jenkins"
description: "Jenkins Operator repository"
repositoryBranch: master
repositoryUrl: https://github.com/jenkinsci/kubernetes-operator.git
```
Now you can deploy it with:
```bash
kubectl apply -n jenkins -f jenkins-instance.yaml
```
With this, you have just set up Jenkins Operator and Jenkins in separate namespaces. Now the Operator will run in
its own namespace (`jenkins-operator`), watch for CRs in `jenkins` namespace, and deploy Jenkins there.