Add website template

This commit is contained in:
Tomasz Sęk
2019-09-04 16:01:25 +02:00
parent 43be3501fd
commit d110a92f6e
238 changed files with 43014 additions and 0 deletions
@@ -0,0 +1,17 @@
---
title: "Getting Started"
linkTitle: "Getting Started"
weight: 10
date: 2019-08-05
description: >
How to work with jenkins-operator
---
{{% pageinfo %}}
This document describes a getting started guide for **jenkins-operator**
{{% /pageinfo %}}
## First Steps
Prepare your Kubernetes cluster and set up access.
Once you have running Kubernetes cluster you can focus on installing **jenkins-operator** according to the [Installation](/docs/installation/) guide.
@@ -0,0 +1,17 @@
---
title: "v0.1.1"
linkTitle: "v0.1.1"
weight: 10
date: 2019-08-05
description: >
How to work with jenkins-operator legacy version. We recommend migration to v0.2.0 version
---
{{% pageinfo %}}
This document describes a getting started guide for **jenkins-operator** `v0.1.1` and an additional configuration.
{{% /pageinfo %}}
## First Steps
Prepare your Kubernetes cluster and set up access.
Once you have running Kubernetes cluster you can focus on installing **jenkins-operator** according to the [Installation](/docs/installation/) guide.
@@ -0,0 +1,24 @@
---
title: "AKS"
linkTitle: "AKS"
weight: 10
date: 2019-08-05
description: >
Additional configuration for Azure Kubernetes Service
---
Azure AKS managed Kubernetes service adds to every pod the following envs:
```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 envs when checking if Jenkins pod envs have been changed. It prevents
restart Jenkins pod over and over again.
@@ -0,0 +1,278 @@
---
title: "Configuration"
linkTitle: "Configuration"
weight: 2
date: 2019-08-05
description: >
How to configure Jenkins with Operator
---
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
│   └── build.jenkins
└── pipelines
└── build.jenkins
```
**cicd/jobs/build.jenkins** it's a job definition:
```
#!/usr/bin/env groovy
pipelineJob('build-jenkins-operator') {
displayName('Build jenkins-operator')
definition {
cpsScm {
scm {
git {
remote {
url('https://github.com/jenkinsci/kubernetes-operator.git')
credentials('jenkins-operator')
}
branches('*/master')
}
}
scriptPath('cicd/pipelines/build.jenkins')
}
}
}
```
**cicd/jobs/build.jenkins** it's an actual Jenkins pipeline:
```
#!/usr/bin/env groovy
def label = "build-jenkins-operator-${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: 'jnlp', image: 'jenkins/jnlp-slave:alpine'),
containerTemplate(name: 'go', image: 'golang:1-alpine', command: 'cat', ttyEnabled: true),
],
envVars: [
envVar(key: 'GOPATH', value: workspace),
],
) {
node(label) {
dir(workdir) {
stage('Init') {
timeout(time: 3, unit: 'MINUTES') {
checkout scm
}
container('go') {
sh 'apk --no-cache --update add make git gcc libc-dev'
}
}
stage('Dep') {
container('go') {
sh 'make dep'
}
}
stage('Test') {
container('go') {
sh 'make test'
}
}
stage('Build') {
container('go') {
sh 'make build'
}
}
}
}
}
```
## 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 seed jobs.
You can verify if deploy keys were successfully configured in Jenkins **Credentials** tab.
![jenkins](/img/jenkins-credentials.png)
You can verify if your pipelines were successfully configured in Jenkins Seed Job console output.
![jenkins](/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 seed job like:
```
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 Kubernetes Secret(name of secret should be the same from `credentialID` field):
```
apiVersion: v1
kind: Secret
metadata:
name: k8s-ssh
stringData:
privateKey: |
-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEAxxDpleJjMCN5nusfW/AtBAZhx8UVVlhhhIKXvQ+dFODQIdzO
oDXybs1zVHWOj31zqbbJnsfsVZ9Uf3p9k6xpJ3WFY9b85WasqTDN1xmSd6swD4N8
...
username: github_user_name
```
### Username & password authentication
Configure 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 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
```
## Jenkins login credentials
The operator automatically generate Jenkins user name and password and stores it in Kubernetes secret named
`jenkins-operator-credentials-<cr_name>` in namespace where Jenkins CR has been deployed.
If you want change it you can override the secret:
```yaml
apiVersion: v1
kind: Secret
metadata:
name: jenkins-operator-credentials-<cr-name>
namespace: <namespace>
data:
user: <base64-encoded-new-username>
password: <base64-encoded-new-password>
```
If needed **jenkins-operator** will restart Jenkins master pod and then you can login with the new user and password
credentials.
## Override default Jenkins container command
The default command for the Jenkins master container `jenkins/jenkins:lts` looks like:
```yaml
command:
- bash
- -c
- /var/jenkins/scripts/init.sh && /sbin/tini -s -- /usr/local/bin/jenkins.sh
```
The script`/var/jenkins/scripts/init.sh` is provided be the operator and configures init.groovy.d(creates Jenkins user)
and installs plugins.
The `/sbin/tini -s -- /usr/local/bin/jenkins.sh` command runs the Jenkins master main process.
You can overwrite it in the following pattern:
```yaml
command:
- bash
- -c
- /var/jenkins/scripts/init.sh && <custom-code-here> && /sbin/tini -s -- /usr/local/bin/jenkins.sh
```
[job-dsl]:https://github.com/jenkinsci/job-dsl-plugin
[kubernetes-credentials-provider]:https://jenkinsci.github.io/kubernetes-credentials-provider-plugin/
@@ -0,0 +1,84 @@
---
title: "Configure backup and restore"
linkTitle: "Configure backup and restore"
weight: 10
date: 2019-08-05
description: >
Prevent job history loss
---
Backup and restore is done by container sidecar.
#### Create PVC
Save to file pvc.yaml:
```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: <pvc_name>
namespace: <namesapce>
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Gi
```
Run command:
```bash
$ kubectl -n <namesapce> create -f pvc.yaml
```
#### Configure Jenkins CR
```yaml
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: <cr_name>
namespace: <namespace>
spec:
master:
securityContext:
runAsUser: 1000
fsGroup: 1000
containers:
- name: jenkins-master
image: jenkins/jenkins:lts
- name: backup # container responsible for 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.0.6 # look at backup/pvc directory
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /jenkins-home # Jenkins home volume
name: jenkins-home
- mountPath: /backup # backup volume
name: backup
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 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
```
@@ -0,0 +1,116 @@
---
title: "Customization"
linkTitle: "Customization"
weight: 3
date: 2019-08-05
description: >
How to customize Jenkins
---
Jenkins can be customized using groovy scripts or configuration as code plugin. All custom configuration is stored in
the **jenkins-operator-user-configuration-<cr_name>** ConfigMap which is automatically created by **jenkins-operator**.
**jenkins-operator** creates **jenkins-operator-user-configuration-<cr_name>** secret where user can store sensitive
information used for custom configuration. If you have entry in secret named `PASSWORD` then you can use it in
Configuration as Plugin as `adminAddress: "${PASSWORD}"`.
```
kubectl get secret jenkins-operator-user-configuration-<cr_name> -o yaml
kind: Secret
apiVersion: v1
type: Opaque
metadata:
name: jenkins-operator-user-configuration-<cr_name>
namespace: default
data:
SECRET_JENKINS_ADMIN_ADDRESS: YXNkZgo=
```
```
kubectl get configmap jenkins-operator-user-configuration-<cr_name> -o yaml
apiVersion: v1
data:
1-configure-theme.groovy: |2
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: |2
jenkins:
systemMessage: "Configuration as Code integration works!!!"
adminAddress: "${SECRET_JENKINS_ADMIN_ADDRESS}"
kind: ConfigMap
metadata:
name: jenkins-operator-user-configuration-<cr_name>
namespace: default
```
When **jenkins-operator-user-configuration-<cr_name>** ConfigMap is updated Jenkins automatically
runs the **jenkins-operator-user-configuration** Jenkins Job which executes all scripts then
runs the **jenkins-operator-user-configuration-casc** Jenkins Job which applies Configuration as Code configuration.
## Install Plugins
Edit CR under `spec.master.plugins`:
```
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
spec:
master:
plugins:
- name: simple-theme-plugin
version: 0.5.1
```
Under `spec.master.basePlugins` you can find plugins for valid **jenkins-operator** work:
```yaml
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
spec:
master:
basePlugins:
- name: kubernetes
version: 1.18.3
- name: workflow-job
version: "2.34"
- name: workflow-aggregator
version: "2.6"
- name: git
version: 3.12.0
- name: job-dsl
version: "1.76"
- name: configuration-as-code
version: "1.29"
- name: configuration-as-code-support
version: "1.19"
- name: kubernetes-credentials-provider
version: 0.12.1
```
You can change version of them.
Then **jenkins-operator** will automatically install plugins after Jenkins master pod restart.
@@ -0,0 +1,91 @@
---
title: "Deploy Jenkins"
linkTitle: "Deploy Jenkins"
weight: 1
date: 2019-08-05
description: >
Deploy production ready Jenkins Operator manifest
---
## Deploy Jenkins
Once jenkins-operator is up and running let's deploy actual Jenkins instance.
Create manifest ie. **jenkins_instance.yaml** with following data and save it on drive.
```bash
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
spec:
master:
containers:
- name: jenkins-master
image: jenkins/jenkins:lts
imagePullPolicy: Always
livenessProbe:
failureThreshold: 12
httpGet:
path: /login
port: http
scheme: HTTP
initialDelaySeconds: 80
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
readinessProbe:
failureThreshold: 3
httpGet:
path: /login
port: http
scheme: HTTP
initialDelaySeconds: 30
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 Jenkins to K8s:
```bash
kubectl create -f jenkins_instance.yaml
```
Watch Jenkins instance being created:
```bash
kubectl get pods -w
```
Get 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 Jenkins (minikube):
```bash
minikube service jenkins-operator-http-<cr_name> --url
```
Connect to Jenkins (actual Kubernetes cluster):
```bash
kubectl port-forward jenkins-<cr_name> 8080:8080
```
Then open browser with address `http://localhost:8080`.
![jenkins](/img/jenkins.png)
@@ -0,0 +1,42 @@
---
title: "Diagnostics"
linkTitle: "Diagnostics"
weight: 40
date: 2019-08-05
description: >
How to deal with jenkins-operator problems
---
Turn on debug in **jenkins-operator** deployment:
```bash
sed -i 's|\(args:\).*|\1\ ["--debug"\]|' deploy/operator.yaml
kubectl apply -f deploy/operator.yaml
```
Watch Kubernetes events:
```bash
kubectl get events --sort-by='{.lastTimestamp}'
```
Verify Jenkins master logs:
```bash
kubectl logs -f jenkins-<cr_name>
```
Verify jenkins-operator logs:
```bash
kubectl logs deployment/jenkins-operator
```
## Troubleshooting
Delete Jenkins master pod and wait for the new one to come up:
```bash
kubectl delete pod jenkins-<cr_name>
```
@@ -0,0 +1,338 @@
---
title: "Migration guide from v1alpha1 to v1alpha2"
linkTitle: "Migration guide from v1alpha1 to v1alpha2"
weight: 50
date: 2019-08-05
description: >
How to migrate to new CRD manifest
---
Please not that **CRD manifests are global**, not namespaced, so every jenkins operator running on the cluster
will be impacted by the new CRD manifest. Multiple operator instances with different versions *should* continue to work.
## Stop jenkins-operator pod
Run command:
```bash
$ kubectl -n <namespace> scale deployment.apps/jenkins-operator --replicas=0
deployment.apps/jenkins-operator scaled
```
Desired state:
```bash
$ kubectl -n <namespace> get po
No resources found.
```
## Stop Jenkins master pod
Run command:
```bash
$ kubectl -n <namespace> get po
NAME READY STATUS RESTARTS AGE
jenkins-operator-<cr_name> 2/2 Running 0 3m35s
$ kubectl -n <namespace> get delete po jenkins-operator-<cr_name>
pod "jenkins-operator-<cr_name>" deleted
```
Desired state:
```bash
$ kubectl -n <namespace> get po
No resources found.
```
## Save Jenkins CR to jenkins.yaml file
Run command:
```bash
$ kubectl -n <namespace> get jenkins <cr_name> -o yaml > jenkins.yaml
```
## Modify jenkins.yaml file
Change apiVersion to `apiVersion: jenkins.io/v1alpha2`
New plugin format without dependent plugins:
- `spec.master.basePlugins` example:
```
spec:
master:
basePlugins:
- name: a-plugin-name
version: "1.0.0"
...
```
- `spec.master.plugins` example:
```
spec:
master:
plugins:
- name: a-plugin-name
version: "1.0.0"
...
```
Move Jenkins `master` container properties to `spec.master.containers[jenkins-master]` (non exhaustive list):
- `spec.master.image` -> `spec.master.containers[jenkins-master].image`
- `spec.master.imagePullPolicy` -> `spec.master.containers[jenkins-master].imagePullPolicy`
- `spec.master.livenessProbe` -> `spec.master.containers[jenkins-master].livenessProbe`
- `spec.master.readinessProbe` -> `spec.master.containers[jenkins-master].readinessProbe`
- `spec.master.resources` -> `spec.master.containers[jenkins-master].resources`
- `spec.master.env` -> `spec.master.containers[jenkins-master].env`
```
spec:
master:
containers:
- name: jenkins-master
image: jenkins/jenkins:lts
...
```
See also the examples bellow for more details. For even more details please look at the source code.
Code that defines the data structures can be found [here](v0.1.1/jenkins-v1alpha2-scheme.md)
### Examples
Old format:
```yaml
apiVersion: jenkins.io/v1alpha1
kind: Jenkins
metadata:
name: <cr_name>
namespace: <namespace>
spec:
master:
basePlugins:
configuration-as-code:1.17:
- configuration-as-code-support:1.17
git:3.10.0:
- apache-httpcomponents-client-4-api:4.5.5-3.0
- credentials:2.1.19
- display-url-api:2.3.1
- git-client:2.7.7
- jsch:0.1.55
- junit:1.28
- mailer:1.23
- matrix-project:1.14
- scm-api:2.4.1
- script-security:1.59
- ssh-credentials:1.16
- structs:1.19
- workflow-api:2.34
- workflow-scm-step:2.7
- workflow-step-api:2.19
job-dsl:1.74:
- script-security:1.59
- structs:1.19
kubernetes-credentials-provider:0.12.1:
- credentials:2.1.19
- structs:1.19
- variant:1.2
kubernetes:1.15.5:
- apache-httpcomponents-client-4-api:4.5.5-3.0
- cloudbees-folder:6.8
- credentials:2.1.19
- durable-task:1.29
- jackson2-api:2.9.9
- kubernetes-credentials:0.4.0
- plain-credentials:1.5
- structs:1.19
- variant:1.2
- workflow-step-api:2.19
workflow-aggregator:2.6:
- ace-editor:1.1
- apache-httpcomponents-client-4-api:4.5.5-3.0
- authentication-tokens:1.3
- branch-api:2.5.2
- cloudbees-folder:6.8
- credentials-binding:1.18
- credentials:2.1.19
- display-url-api:2.3.1
- docker-commons:1.15
- docker-workflow:1.18
- durable-task:1.29
- git-client:2.7.7
- git-server:1.7
- handlebars:1.1.1
- jackson2-api:2.9.9
- jquery-detached:1.2.1
- jsch:0.1.55
- junit:1.28
- lockable-resources:2.5
- mailer:1.23
- matrix-project:1.14
- momentjs:1.1.1
- pipeline-build-step:2.9
- pipeline-graph-analysis:1.10
- pipeline-input-step:2.10
- pipeline-milestone-step:1.3.1
- pipeline-model-api:1.3.8
- pipeline-model-declarative-agent:1.1.1
- pipeline-model-definition:1.3.8
- pipeline-model-extensions:1.3.8
- pipeline-rest-api:2.11
- pipeline-stage-step:2.3
- pipeline-stage-tags-metadata:1.3.8
- pipeline-stage-view:2.11
- plain-credentials:1.5
- scm-api:2.4.1
- script-security:1.59
- ssh-credentials:1.16
- structs:1.19
- workflow-api:2.34
- workflow-basic-steps:2.16
- workflow-cps-global-lib:2.13
- workflow-cps:2.69
- workflow-durable-task-step:2.30
- workflow-job:2.32
- workflow-multibranch:2.21
- workflow-scm-step:2.7
- workflow-step-api:2.19
- workflow-support:3.3
workflow-job:2.32:
- scm-api:2.4.1
- script-security:1.59
- structs:1.19
- workflow-api:2.34
- workflow-step-api:2.19
- workflow-support:3.3
image: jenkins/jenkins:lts
imagePullPolicy: Always
livenessProbe:
failureThreshold: 12
httpGet:
path: /login
port: 8080
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
plugins:
simple-theme-plugin:0.5.1: []
slack:2.24:
- workflow-step-api:2.19
- credentials:2.1.19
- display-url-api:2.3.1
- junit:1.28
- plain-credentials:1.5
- script-security:1.59
- structs:1.19
- token-macro:2.8
readinessProbe:
failureThreshold: 12
httpGet:
path: /login
port: 8080
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
resources:
limits:
cpu: 1500m
memory: 3Gi
requests:
cpu: "1"
memory: 500Mi
```
New format:
```yaml
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: <cr_name>
namespace: <namespace>
spec:
master:
basePlugins:
- name: kubernetes
version: 1.15.7
- name: workflow-job
version: "2.32"
- name: workflow-aggregator
version: "2.6"
- name: git
version: 3.10.0
- name: job-dsl
version: "1.74"
- name: configuration-as-code
version: "1.19"
- name: configuration-as-code-support
version: "1.19"
- name: kubernetes-credentials-provider
version: 0.12.1
containers:
- name: jenkins-master
image: jenkins/jenkins:lts
imagePullPolicy: Always
livenessProbe:
failureThreshold: 12
httpGet:
path: /login
port: http
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
readinessProbe:
failureThreshold: 3
httpGet:
path: /login
port: http
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
resources:
limits:
cpu: 1500m
memory: 3Gi
requests:
cpu: "1"
memory: 500Mi
plugins:
- name: simple-theme-plugin
version: 0.5.1
- name: slack
version: 2.24
```
## Update CRD to new version
New version of the Custom Resource definition for the operator needs to be applied:
-[Jenkins CRD v1alpha2](https://github.com/jenkinsci/kubernetes-operator/blob/master/deploy/crds/jenkins_v1alpha2_jenkins_crd.yaml)
To use default CRD file:
```
kubectl -n <namespace> apply -f https://github.com/jenkinsci/kubernetes-operator/blob/master/deploy/crds/jenkins_v1alpha2_jenkins_crd.yaml
```
## Update RBAC to new version
New operator version requires updated RBAC permissions:
To use default Role file:
```
$ kubectl -n <namespace> apply -f https://raw.githubusercontent.com/jenkinsci/kubernetes-operator/master/deploy/role.yaml
```
## Deploy new operator manifests
Replace your modified operator configuration file:
```bash
$ kubectl -n <namespace> replace -f jenkins.yaml
```
Update operator version in the deployment file to `image: virtuslab/jenkins-operator:v0.1.0` and scale up,
or use the default deployment manifest:
```
$ kubectl -n <namespace> apply -f https://raw.githubusercontent.com/jenkinsci/kubernetes-operator/master/deploy/operator.yaml
```
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,17 @@
---
title: "v0.2.0"
linkTitle: "v0.2.0"
weight: 10
date: 2019-08-05
description: >
How to work with jenkins-operator latest version
---
{{% pageinfo %}}
This document describes a getting started guide for **jenkins-operator** `v0.2.0` and an additional configuration.
{{% /pageinfo %}}
## First Steps
Prepare your Kubernetes cluster and set up access.
Once you have running Kubernetes cluster you can focus on installing **jenkins-operator** according to the [Installation](/docs/installation/) guide.
@@ -0,0 +1,24 @@
---
title: "AKS"
linkTitle: "AKS"
weight: 10
date: 2019-08-05
description: >
Additional configuration for Azure Kubernetes Service
---
Azure AKS managed Kubernetes service adds to every pod the following envs:
```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 envs when checking if Jenkins pod envs have been changed. It prevents
restart Jenkins pod over and over again.
@@ -0,0 +1,308 @@
---
title: "Configuration"
linkTitle: "Configuration"
weight: 2
date: 2019-08-05
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
│   └── build.jenkins
└── pipelines
└── build.jenkins
```
**cicd/jobs/build.jenkins** it's a job definition:
```
#!/usr/bin/env groovy
pipelineJob('build-jenkins-operator') {
displayName('Build jenkins-operator')
definition {
cpsScm {
scm {
git {
remote {
url('https://github.com/jenkinsci/kubernetes-operator.git')
credentials('jenkins-operator')
}
branches('*/master')
}
}
scriptPath('cicd/pipelines/build.jenkins')
}
}
}
```
**cicd/jobs/build.jenkins** it's an actual Jenkins pipeline:
```
#!/usr/bin/env groovy
def label = "build-jenkins-operator-${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: 'jnlp', image: 'jenkins/jnlp-slave:alpine'),
containerTemplate(name: 'go', image: 'golang:1-alpine', command: 'cat', ttyEnabled: true),
],
envVars: [
envVar(key: 'GOPATH', value: workspace),
],
) {
node(label) {
dir(workdir) {
stage('Init') {
timeout(time: 3, unit: 'MINUTES') {
checkout scm
}
container('go') {
sh 'apk --no-cache --update add make git gcc libc-dev'
}
}
stage('Dep') {
container('go') {
sh 'make dep'
}
}
stage('Test') {
container('go') {
sh 'make test'
}
}
stage('Build') {
container('go') {
sh 'make build'
}
}
}
}
}
```
## 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 seed jobs.
You can verify if deploy keys were successfully configured in Jenkins **Credentials** tab.
![jenkins](/img/jenkins-credentials.png)
You can verify if your pipelines were successfully configured in Jenkins Seed Job console output.
![jenkins](/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 seed job like:
```
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 Kubernetes Secret(name of secret should be the same from `credentialID` field):
```
apiVersion: v1
kind: Secret
metadata:
name: k8s-ssh
stringData:
privateKey: |
-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEAxxDpleJjMCN5nusfW/AtBAZhx8UVVlhhhIKXvQ+dFODQIdzO
oDXybs1zVHWOj31zqbbJnsfsVZ9Uf3p9k6xpJ3WFY9b85WasqTDN1xmSd6swD4N8
...
username: github_user_name
```
### Username & password authentication
Configure 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 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
```
## Pulling Docker images from private repositories
To pull 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 Base64 value before setting the `.dockerconfigjson` key:q.
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/
@@ -0,0 +1,86 @@
---
title: "Configure backup and restore"
linkTitle: "Configure backup and restore"
weight: 10
date: 2019-08-05
description: >
Prevent job history loss
---
Backup and restore is done by container sidecar.
### PVC
#### Create PVC
Save to file pvc.yaml:
```yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: <pvc_name>
namespace: <namesapce>
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Gi
```
Run command:
```bash
$ kubectl -n <namesapce> create -f pvc.yaml
```
#### Configure Jenkins CR
```yaml
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: <cr_name>
namespace: <namespace>
spec:
master:
securityContext:
runAsUser: 1000
fsGroup: 1000
containers:
- name: jenkins-master
image: jenkins/jenkins:lts
- name: backup # container responsible for 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.0.6 # look at backup/pvc directory
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /jenkins-home # Jenkins home volume
name: jenkins-home
- mountPath: /backup # backup volume
name: backup
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 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
```
@@ -0,0 +1,186 @@
---
title: "Customization"
linkTitle: "Customization"
weight: 3
date: 2019-08-05
description: >
How to customize Jenkins
---
Jenkins can be customized using groovy scripts or [configuration as code plugin](https://github.com/jenkinsci/configuration-as-code-plugin).
By using [ConfigMap](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/) you can create own **Jenkins** customized configuration.
Then you must reference the *ConfigMap* in **Jenkins** pod customization file in `spec.groovyScripts` or `spec.configurationAsCode`
For example create *ConfigMap* with name `jenkins-operator-user-configuration`. Then, modify the **Jenkins** manifest to look like this:
```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 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 **jenkins-operator** is running.
Jenkins will reconcile and apply new configuration.
### Using secrets inside Groovy script
If you configured `spec.groovyScripts.secret.name`, then this secret is available to use inside map Groovy scripts.
The secrets are loaded to `secrets` map.
Create a [secret](https://kubernetes.io/docs/concepts/configuration/secret/) with for eg. `jenkins-conf-secrets` name.
```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 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 at **Jenkins** homepage.
## Install Plugins
Edit CR under `spec.master.plugins`:
```
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
spec:
master:
plugins:
- name: simple-theme-plugin
version: 0.5.1
```
Under `spec.master.basePlugins` you can find plugins for valid **jenkins-operator** work:
```yaml
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
spec:
master:
basePlugins:
- name: kubernetes
version: 1.18.3
- name: workflow-job
version: "2.34"
- name: workflow-aggregator
version: "2.6"
- name: git
version: 3.12.0
- name: job-dsl
version: "1.76"
- name: configuration-as-code
version: "1.29"
- name: configuration-as-code-support
version: "1.19"
- name: kubernetes-credentials-provider
version: 0.12.1
```
You can change version of them.
Then **jenkins-operator** will automatically install plugins after Jenkins master pod restart.
@@ -0,0 +1,89 @@
---
title: "Deploy Jenkins"
linkTitle: "Deploy Jenkins"
weight: 1
date: 2019-08-05
description: >
Deploy production ready Jenkins Operator manifest
---
Once jenkins-operator is up and running let's deploy actual Jenkins instance.
Create manifest ie. **jenkins_instance.yaml** with following data and save it on drive.
```bash
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
spec:
master:
containers:
- name: jenkins-master
image: jenkins/jenkins:lts
imagePullPolicy: Always
livenessProbe:
failureThreshold: 12
httpGet:
path: /login
port: http
scheme: HTTP
initialDelaySeconds: 80
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
readinessProbe:
failureThreshold: 3
httpGet:
path: /login
port: http
scheme: HTTP
initialDelaySeconds: 30
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 Jenkins to K8s:
```bash
kubectl create -f jenkins_instance.yaml
```
Watch Jenkins instance being created:
```bash
kubectl get pods -w
```
Get 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 Jenkins (minikube):
```bash
minikube service jenkins-operator-http-<cr_name> --url
```
Connect to Jenkins (actual Kubernetes cluster):
```bash
kubectl port-forward jenkins-<cr_name> 8080:8080
```
Then open browser with address `http://localhost:8080`.
![jenkins](/img/jenkins.png)
@@ -0,0 +1,42 @@
---
title: "Diagnostics"
linkTitle: "Diagnostics"
weight: 40
date: 2019-08-05
description: >
How to deal with jenkins-operator problems
---
Turn on debug in **jenkins-operator** deployment:
```bash
sed -i 's|\(args:\).*|\1\ ["--debug"\]|' deploy/operator.yaml
kubectl apply -f deploy/operator.yaml
```
Watch Kubernetes events:
```bash
kubectl get events --sort-by='{.lastTimestamp}'
```
Verify Jenkins master logs:
```bash
kubectl logs -f jenkins-<cr_name>
```
Verify jenkins-operator logs:
```bash
kubectl logs deployment/jenkins-operator
```
## Troubleshooting
Delete Jenkins master pod and wait for the new one to come up:
```bash
kubectl delete pod jenkins-<cr_name>
```
@@ -0,0 +1,39 @@
---
title: "Migration from v0.1.1"
linkTitle: "Migration from v0.1.1"
weight: 10
date: 2019-08-05
description: >
How to migrate from v0.1.1 to v0.2.0
---
### Added seed job agent
Now seed jobs are not built by master executors, but by dedicated agent deployed into Kubernetes. We disabled master executors for security reasons.
### Apply Jenkins configuration via Groovy scripts instead of Jenkins jobs
We have removed hardcoded configuration by **Jenkins** jobs.
In `v0.1.1` **jenkins-operator** configuration was stored in `jenkins-operator-user-configuration-<cr_name>`
If you want to use `v0.2.0` or newer you must simply write refer to old ConfigMap by modifying CR, for example:
```yaml
apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
name: example
spec:
configurationAsCode:
configurations:
- name: jenkins-operator-user-configuration-<cr_name>
groovyScripts:
configurations:
- name: jenkins-operator-user-configuration-<cr_name>
```
**Jenkins** configuration jobs (*Configure Seed Jobs*, *jenkins-operator-base-configuration*, *jenkins-operator-user-configuration*) have been removed from **Jenkins**.
In `v0.1.1` you can see if configuration failed or successfully updated in **Jenkins** UI (job build logs).
Now, when Jenkins configuration jobs are removed, you must use this command to see if configuration was failed.
```bash
$ kubectl -n logs deployment/jenkins-operator
```
File diff suppressed because it is too large Load Diff