#157 Improved website documentation, removed old github docs
This commit is contained in:
parent
e907dfe0b4
commit
0102c181a9
10
README.md
10
README.md
|
|
@ -27,14 +27,14 @@ We want to make Jenkins more robust, suitable for dynamic and multi-tenant envir
|
|||
|
||||
Some of the problems we want to solve:
|
||||
- volumes handling (AWS EBS volume attach/detach issue when using PVC)
|
||||
- installing plugins with incompatible versions or security vulnerabilities
|
||||
- better configuration as code
|
||||
- [installing plugins with incompatible versions or security vulnerabilities](https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/customization/#install-plugins)
|
||||
- [better configuration as code](https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/customization/)
|
||||
- lack of end to end tests
|
||||
- handle graceful shutdown properly
|
||||
- security and hardening out of the box
|
||||
- [security and hardening out of the box](https://jenkinsci.github.io/kubernetes-operator/docs/security/)
|
||||
- orphaned jobs with no jnlp connection
|
||||
- make errors more visible for end users
|
||||
- backup and restore for jobs history
|
||||
- [make errors more visible for end users](https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/diagnostics/)
|
||||
- [backup and restore for jobs history](https://jenkinsci.github.io/kubernetes-operator/docs/getting-started/latest/configure-backup-and-restore/)
|
||||
|
||||
## Documentation
|
||||
|
||||
|
|
|
|||
|
|
@ -1,142 +0,0 @@
|
|||
# Developer guide
|
||||
|
||||
This document explains how to setup your development environment.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- [operator_sdk][operator_sdk] version v0.8.1
|
||||
- [git][git_tool]
|
||||
- [go][go_tool] version v1.12+
|
||||
- [goimports, golint, checkmake and staticcheck][install_dev_tools]
|
||||
- [minikube][minikube] version v1.1.0+ (preferred Hypervisor - [virtualbox][virtualbox])
|
||||
- [docker][docker_tool] version 17.03+
|
||||
|
||||
## Clone repository and download dependencies
|
||||
|
||||
```bash
|
||||
mkdir -p $GOPATH/src/github.com/jenkinsci
|
||||
cd $GOPATH/src/github.com/jenkinsci/
|
||||
git clone git@github.com:jenkinsci/kubernetes-operator.git
|
||||
cd kubernetes-operator
|
||||
make go-dependencies
|
||||
```
|
||||
|
||||
## Build and run with a minikube
|
||||
|
||||
Build and run **Jenkins Operator** locally:
|
||||
|
||||
```bash
|
||||
make build minikube-run EXTRA_ARGS='--minikube --local'
|
||||
```
|
||||
|
||||
Once minikube and **Jenkins Operator** are up and running, apply Jenkins custom resource:
|
||||
|
||||
```bash
|
||||
kubectl apply -f deploy/crds/jenkins_v1alpha2_jenkins_cr.yaml
|
||||
kubectl get jenkins -o yaml
|
||||
kubectl get po
|
||||
```
|
||||
|
||||
## Build and run with a remote Kubernetes cluster
|
||||
|
||||
You can also run the controller locally and make it listen to a remote Kubernetes server.
|
||||
|
||||
```bash
|
||||
make run NAMESPACE=default KUBECTL_CONTEXT=remote-k8s EXTRA_ARGS='--kubeconfig ~/.kube/config'
|
||||
```
|
||||
|
||||
Once minikube and **Jenkins Operator** are up and running, apply Jenkins custom resource:
|
||||
|
||||
```bash
|
||||
kubectl --context remote-k8s --namespace default apply -f deploy/crds/jenkins_v1alpha2_jenkins_cr.yaml
|
||||
kubectl --context remote-k8s --namespace default get jenkins -o yaml
|
||||
kubectl --context remote-k8s --namespace default get po
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Run unit tests:
|
||||
|
||||
```bash
|
||||
make test
|
||||
```
|
||||
|
||||
### Running E2E tests on Linux
|
||||
|
||||
Run e2e tests with minikube:
|
||||
|
||||
```bash
|
||||
make minikube-start
|
||||
eval $(minikube docker-env)
|
||||
make build e2e
|
||||
```
|
||||
|
||||
Run the specific e2e test:
|
||||
|
||||
```bash
|
||||
make build e2e E2E_TEST_SELECTOR='^TestConfiguration$'
|
||||
```
|
||||
|
||||
### Running E2E tests on macOS
|
||||
|
||||
At first, you need to start minikube:
|
||||
```bash
|
||||
$ make minikube-start
|
||||
$ eval $(minikube docker-env)
|
||||
```
|
||||
|
||||
Build Docker image inside provided Linux container by:
|
||||
```bash
|
||||
$ make indocker
|
||||
```
|
||||
|
||||
Build **Jenkins Operator** inside container using:
|
||||
|
||||
```bash
|
||||
$ make build
|
||||
```
|
||||
|
||||
Then exit the container and run:
|
||||
```
|
||||
make e2e
|
||||
```
|
||||
|
||||
## Tips & Tricks
|
||||
|
||||
### Building docker image on minikube (for e2e tests)
|
||||
|
||||
To be able to work with the docker daemon on `minikube` machine run the following command before building an image:
|
||||
|
||||
```bash
|
||||
eval $(minikube docker-env)
|
||||
```
|
||||
|
||||
### When `pkg/apis/jenkinsio/*/jenkins_types.go` has changed
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
make deepcopy-gen
|
||||
```
|
||||
|
||||
### Getting Jenkins URL and basic credentials
|
||||
|
||||
```bash
|
||||
minikube service jenkins-operator-http-<cr_name> --url
|
||||
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
|
||||
```
|
||||
|
||||
|
||||
[dep_tool]:https://golang.github.io/dep/docs/installation.html
|
||||
[git_tool]:https://git-scm.com/downloads
|
||||
[go_tool]:https://golang.org/dl/
|
||||
[operator_sdk]:https://github.com/operator-framework/operator-sdk
|
||||
[fork_guide]:https://help.github.com/articles/fork-a-repo/
|
||||
[docker_tool]:https://docs.docker.com/install/
|
||||
[kubectl_tool]:https://kubernetes.io/docs/tasks/tools/install-kubectl/
|
||||
[minikube]:https://kubernetes.io/docs/tasks/tools/install-minikube/
|
||||
[virtualbox]:https://www.virtualbox.org/wiki/Downloads
|
||||
[jenkins-operator]:../README.md
|
||||
[install_dev_tools]:install_dev_tools.md
|
||||
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
# How it works
|
||||
|
||||
This document describes a high level overview how **Jenkins Operator** works.
|
||||
|
||||
1. [Architecture and design](#architecture-and-design)
|
||||
2. [Operator State](#operator-state)
|
||||
3. [System Jenkins Jobs](#system-jenkins-jobs)
|
||||
3. [Jenkins Docker Images](#jenkins-docker-images)
|
||||
|
||||
## Architecture and design
|
||||
|
||||
The **Jenkins Operator** design incorporates the following concepts:
|
||||
- watches any changes of manifests and maintain the desired state according to deployed custom resource manifest
|
||||
- implements the main reconciliation loop which consists of two smaller reconciliation loops - base and user
|
||||
|
||||

|
||||
|
||||
**Base** reconciliation loop takes care of reconciling base Jenkins configuration, which consists of:
|
||||
- Ensure Manifests - monitors any changes in manifests
|
||||
- Ensure Jenkins Pod - creates and verifies status of Jenkins master Pod
|
||||
- Ensure Jenkins Configuration - configures Jenkins instance including hardening, initial configuration for plugins, etc.
|
||||
- Ensure Jenkins API token - generates Jenkins API token and initialized Jenkins client
|
||||
|
||||
**User** reconciliation loop takes care of reconciling user provided configuration, which consists of:
|
||||
- Ensure Restore Job - creates Restore job and ensures that restore has been successfully performed
|
||||
- Ensure Seed Jobs - creates Seed Jobs and ensures that all of them have been successfully executed
|
||||
- Ensure User Configuration - executed user provided configuration, like groovy scripts, configuration as code or plugins
|
||||
- Ensure Backup Job - creates Backup job and ensures that backup has been successfully performed
|
||||
|
||||

|
||||
|
||||
## Operator State
|
||||
|
||||
Operator state is kept in custom resource status section, which is used for storing any configuration events or job statuses managed by the operator.
|
||||
It helps to maintain or recover desired state even after operator or Jenkins restarts.
|
||||
|
||||
## System Jenkins Jobs
|
||||
|
||||
The operator or Jenkins instance can be restarted at any time and any operation should not block the reconciliation loop.
|
||||
Taking this into account we implemented custom jobs API for executing system jobs (seed jobs, groovy scripts, etc.) according to the operator lifecycle.
|
||||
|
||||
Main assumptions are:
|
||||
- do not block reconciliation loop
|
||||
- fire job, requeue reconciliation loop and verify job status next time
|
||||
- handle retries if case of failure
|
||||
- handle build expiration (deadline)
|
||||
- keep state in the custom resource status section
|
||||
|
||||
## Jenkins Docker Images
|
||||
|
||||
**Jenkins Operator** is fully compatible with **jenkins:lts** docker image and does not introduce any hidden changes there.
|
||||
If needed, the docker image can easily be changed in custom resource manifest as long as it supports standard Jenkins file system structure.
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
# Installation of the required development tools
|
||||
|
||||
This document explains how to install the Go tools used by the development process.
|
||||
|
||||
## Configure environment variables
|
||||
|
||||
```bash
|
||||
export GOPATH=/home/go # example value
|
||||
export GOROOT=/usr/lib/go-1.12 # example value
|
||||
export PATH=$GOPATH/bin:$PATH
|
||||
```
|
||||
|
||||
## goimports
|
||||
|
||||
```
|
||||
go get golang.org/x/tools/cmd/goimports
|
||||
cd $GOPATH/src/golang.org/x/tools/cmd/goimports
|
||||
go build
|
||||
go install
|
||||
```
|
||||
|
||||
## golint
|
||||
|
||||
```
|
||||
go get -u golang.org/x/lint/golint
|
||||
cd $GOPATH/src/golang.org/x/lint/golint
|
||||
go build
|
||||
go install
|
||||
```
|
||||
|
||||
## checkmake
|
||||
```
|
||||
go get github.com/mrtazz/checkmake
|
||||
cd $GOPATH/src/github.com/mrtazz/checkmake
|
||||
go build
|
||||
go install
|
||||
```
|
||||
|
||||
## staticcheck
|
||||
|
||||
```
|
||||
mkdir -p $GOPATH/src/github.com/dominikh/
|
||||
cd $GOPATH/src/github.com/dominikh/
|
||||
git clone https://github.com/dominikh/go-tools.git
|
||||
cd $GOPATH/src/github.com/dominikh/go-tools/staticcheck
|
||||
go build
|
||||
go install
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
# Installation
|
||||
|
||||
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)
|
||||
|
||||
## Requirements
|
||||
|
||||
To run **Jenkins Operator**, you will need:
|
||||
- running Kubernetes cluster version 1.11+
|
||||
- kubectl version 1.11+
|
||||
|
||||
## Configure Custom Resource Definition
|
||||
|
||||
Install Jenkins Custom Resource Definition:
|
||||
|
||||
```bash
|
||||
kubectl apply -f https://raw.githubusercontent.com/jenkinsci/kubernetes-operator/master/deploy/crds/jenkins_v1alpha2_jenkins_crd.yaml
|
||||
```
|
||||
|
||||
## Deploy Jenkins Operator
|
||||
|
||||
Apply Service Account and RBAC roles:
|
||||
|
||||
```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 `default` namespace.
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
# Migration guide 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>
|
||||
secret:
|
||||
name: jenkins-operator-user-configuration-<cr_name>
|
||||
groovyScripts:
|
||||
configurations:
|
||||
- name: jenkins-operator-user-configuration-<cr_name>
|
||||
secret:
|
||||
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
|
||||
```
|
||||
|
|
@ -1,331 +0,0 @@
|
|||
# Migration guide from v1alpha1 to v1alpha2
|
||||
|
||||
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
|
||||
```
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
# Jenkins Security
|
||||
|
||||
By default **Jenkins Operator** performs an initial security hardening of Jenkins instance via groovy scripts to prevent any security gaps.
|
||||
|
||||
## Jenkins Access Control
|
||||
|
||||
Currently **Jenkins Operator** generates a username and random password and stores them in a Kubernetes Secret.
|
||||
However any other authorization mechanisms are possible and can be done via groovy scripts or configuration as code plugin.
|
||||
For more information take a look at [getting-started#jenkins-customization](v0.1.1/getting-started.md#jenkins-customisation).
|
||||
|
||||
Any change to Security Realm or Authorization requires that user called `jenkins-operator` must have admin rights
|
||||
because **Jenkins Operator** calls Jenkins API.
|
||||
|
||||
## Jenkins Hardening
|
||||
|
||||
The list below describes all the default security setting configured by the **Jenkins Operator**:
|
||||
- basic settings - use `Mode.EXCLUSIVE` - Jobs must specify that they want to run on master node
|
||||
- enable CSRF - Cross Site Request Forgery Protection is enabled
|
||||
- disable usage stats - Jenkins usage stats submitting is disabled
|
||||
- enable master access control - Slave To Master Access Control is enabled
|
||||
- disable old JNLP protocols - `JNLP3-connect`, `JNLP2-connect` and `JNLP-connect` are disabled
|
||||
- disable CLI - CLI access of `/cli` URL is disabled
|
||||
- configure kubernetes-plugin - secure configuration for Kubernetes plugin
|
||||
|
||||
If you would like to dig a little bit into the code, take a look [here](../pkg/controller/jenkins/configuration/base/resources/base_configuration_configmap.go).
|
||||
|
||||
## Jenkins API
|
||||
|
||||
The **Jenkins Operator** generates and configures Basic Authentication token for Jenkins go client and stores it in a Kubernetes Secret.
|
||||
|
||||
## Kubernetes
|
||||
|
||||
Kubernetes API permissions are limited by the following roles:
|
||||
- [jenkins-operator role](../deploy/role.yaml)
|
||||
- [Jenkins Master role](../pkg/controller/jenkins/configuration/base/resources/rbac.go)
|
||||
|
||||
Since **Jenkins Operator** must be able to grant permission for its' deployed Jenkins masters to spawn pods (the `Jenkins Master role` above),
|
||||
the operator itself requires permission to create RBAC resources (the `jenkins-operator role` above).
|
||||
Deployed this way, any subject which may create a Pod (including a Jenkins job) may
|
||||
assume the `jenkins-operator` role by using its' ServiceAccount, create RBAC rules, and thus escape its granted permissions.
|
||||
Any namespace to which the `jenkins-operator` is deployed must be considered to implicitly grant all
|
||||
possible permissions to any subject which can create a Pod in that namespace.
|
||||
|
||||
To mitigate this issue **Jenkins Operator** should be deployed in one namespace and the Jenkins CR should be created in separate namespace.
|
||||
To achieve it change watch namespace in https://github.com/jenkinsci/kubernetes-operator/blob/master/deploy/operator.yaml#L25
|
||||
|
||||
## Setup Jenkins Operator and Jenkins in separated 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
|
||||
```
|
||||
|
||||
Next, apply the RBAC manifests for **Jenkins Operator** namespace
|
||||
```bash
|
||||
$ kubectl -n jenkins-operator apply -f deploy/service_account.yaml
|
||||
$ kubectl -n jenkins-operator apply -f deploy/role_binding.yaml
|
||||
```
|
||||
|
||||
Create file role_binding_jenkins.yaml in `deploy` folder:
|
||||
```yaml
|
||||
kind: RoleBinding
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
metadata:
|
||||
name: jenkins-operator
|
||||
namespace: jenkins
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: jenkins-operator
|
||||
namespace: jenkins-operator
|
||||
roleRef:
|
||||
kind: Role
|
||||
name: jenkins-operator
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
```
|
||||
|
||||
Then, apply RBAC rules for **jenkins** namespace
|
||||
```bash
|
||||
$ kubectl -n jenkins apply -f deploy/role.yaml
|
||||
$ kubectl -n jenkins apply -f role_binding_jenkins.yaml
|
||||
```
|
||||
|
||||
Finally, you must create operator pod by:
|
||||
```bash
|
||||
$ kubectl -n jenkins -n jenkins-operator apply -f deploy/operator.yaml
|
||||
```
|
||||
|
||||
|
||||
## Report a Security Vulnerability
|
||||
|
||||
If you find a vulnerability or any misconfiguration in Jenkins, please report it in the [issues](https://github.com/jenkinsci/kubernetes-operator/issues).
|
||||
|
||||
|
||||
|
|
@ -1,586 +0,0 @@
|
|||
# Getting Started
|
||||
|
||||
This document describes a getting started guide for **Jenkins Operator** and an additional configuration.
|
||||
|
||||
1. [First Steps](#first-steps)
|
||||
2. [Deploy Jenkins](#deploy-jenkins)
|
||||
3. [Configure Seed Jobs and Pipelines](#configure-seed-jobs-and-pipelines)
|
||||
4. [Install Plugins](#install-plugins)
|
||||
5. [Configure Backup & Restore](#configure-backup-and-restore)
|
||||
6. [AKS](#aks)
|
||||
7. [Jenkins login credentials](#jenkins-login-credentials)
|
||||
8. [Override default Jenkins container command](#override-default-Jenkins-container-command)
|
||||
9. [Debugging](#debugging)
|
||||
|
||||
## 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](../installation.md) guide.
|
||||
|
||||
## 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`.
|
||||

|
||||
|
||||
## 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/pipelines/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.
|
||||
|
||||

|
||||
|
||||
You can verify if your pipelines were successfully configured in Jenkins Seed Job console output.
|
||||
|
||||

|
||||
|
||||
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 Customisation
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
Then **Jenkins Operator** will automatically install plugins after Jenkins master pod restart.
|
||||
|
||||
## Configure backup and restore
|
||||
|
||||
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: <namespace>
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 500Gi
|
||||
```
|
||||
|
||||
Run command:
|
||||
```bash
|
||||
$ kubectl -n <namespace> 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.7 # 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
|
||||
```
|
||||
|
||||
## AKS
|
||||
|
||||
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.
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
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>
|
||||
```
|
||||
|
||||
[job-dsl]:https://github.com/jenkinsci/job-dsl-plugin
|
||||
[kubernetes-credentials-provider]:https://jenkinsci.github.io/kubernetes-credentials-provider-plugin/
|
||||
|
|
@ -1,731 +0,0 @@
|
|||
# Getting Started
|
||||
|
||||
This document describes a getting started guide for **Jenkins Operator** and an additional configuration.
|
||||
|
||||
1. [First Steps](#first-steps)
|
||||
2. [Deploy Jenkins](#deploy-jenkins)
|
||||
3. [Configure Seed Jobs and Pipelines](#configure-seed-jobs-and-pipelines)
|
||||
4. [Pulling Docker images from private repositories](#pulling-docker-images-from-private-repositories)
|
||||
5. [Jenkins Customisation](#jenkins-customisation)
|
||||
6. [Install Plugins](#install-plugins)
|
||||
7. [Configure Backup & Restore](#configure-backup-and-restore)
|
||||
8. [AKS](#aks)
|
||||
9. [Jenkins login credentials](#jenkins-login-credentials)
|
||||
10. [Override default Jenkins container command](#override-default-Jenkins-container-command)
|
||||
11. [Debugging](#debugging)
|
||||
|
||||
## 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](../installation.md) guide.
|
||||
|
||||
## 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`.
|
||||

|
||||
|
||||
## 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/pipelines/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.
|
||||
|
||||

|
||||
|
||||
You can verify if your pipelines were successfully configured in Jenkins Seed Job console output.
|
||||
|
||||

|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Jenkins Customisation
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
Then **Jenkins Operator** will automatically install plugins after Jenkins master pod restart.
|
||||
|
||||
## Configure backup and restore
|
||||
|
||||
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: <namespace>
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 500Gi
|
||||
```
|
||||
|
||||
Run command:
|
||||
```bash
|
||||
$ kubectl -n <namespace> 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.7 # 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
|
||||
```
|
||||
|
||||
## AKS
|
||||
|
||||
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.
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
## Debugging
|
||||
|
||||
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>
|
||||
```
|
||||
|
||||
[job-dsl]:https://github.com/jenkinsci/job-dsl-plugin
|
||||
[kubernetes-credentials-provider]:https://jenkinsci.github.io/kubernetes-credentials-provider-plugin/
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
[Docsy](https://github.com/google/docsy) is a Hugo theme for technical documentation sites, providing easy site navigation, structure, and more. This **Docsy Example Project** uses the Docsy theme, as well as providing a skeleton documentation structure for you to use. You can either copy this project and edit it with your own content, or use the theme in your projects like any other [Hugo theme](https://gohugo.io/themes/installing-and-using-themes/).
|
||||
|
||||
This Docsy Example Project is hosted at [https://goldydocs.netlify.com/](https://goldydocs.netlify.com/).
|
||||
|
||||
You can find detailed theme instructions in the Docsy user guide: https://docsydocs.netlify.com/docs/
|
||||
|
||||
This is not an officially supported Google product. This project is currently maintained.
|
||||
|
||||
## Cloning the Docsy Example Project
|
||||
|
||||
The following will give you a project that is set up and ready to use (don't forget to use `--recurse-submodules` or you won't pull down some of the code you need to generate a working site). The `hugo server` command builds and serves the site. If you just want to build the site, run `hugo` instead.
|
||||
|
||||
```bash
|
||||
git clone --recurse-submodules --depth 1 https://github.com/google/docsy-example.git
|
||||
cd docsy-example
|
||||
hugo server
|
||||
```
|
||||
|
||||
The theme is included as a Git submodule:
|
||||
|
||||
```bash
|
||||
▶ git submodule
|
||||
a053131a4ebf6a59e4e8834a42368e248d98c01d themes/docsy (heads/master)
|
||||
```
|
||||
|
||||
If you want to do SCSS edits and want to publish these, you need to install `PostCSS` (not needed for `hugo server`):
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
<!--### Cloning the Example from the Theme Project
|
||||
|
||||
|
||||
```bash
|
||||
git clone --recurse-submodules --depth 1 https://github.com/docsy.git
|
||||
cd tech-doc-hugo-theme/exampleSite
|
||||
HUGO_THEMESDIR="../.." hugo server
|
||||
```
|
||||
|
||||
|
||||
Note that the Hugo Theme Site requires the `exampleSite` to live in a subfolder of the theme itself. To avoid recursive duplication, the example site is added as a Git subtree:
|
||||
|
||||
```bash
|
||||
git subtree add --prefix exampleSite https://github.com/google/docsy.git master --squash
|
||||
```
|
||||
|
||||
To pull in changes, see `pull-deps.sh` script in the theme.-->
|
||||
|
||||
## Running the website locally
|
||||
|
||||
Once you've cloned the site repo, from the repo root folder, run:
|
||||
|
||||
```
|
||||
hugo server
|
||||
```
|
||||
|
|
@ -65,7 +65,7 @@ Prevent loss of job history
|
|||
We do a [Pull Request](https://github.com/jenkinsci/kubernetes-operator/pulls) contributions workflow on **GitHub**. New users are always welcome!
|
||||
{{% /blocks/feature %}}
|
||||
|
||||
{{% blocks/feature icon="fas fa-folder-open" title="Documentation" url="/docs/" %}}
|
||||
{{% blocks/feature icon="fas fa-folder-open" title="Documentation" url="/kubernetes-operator/docs" %}}
|
||||
Learning the usage of Jenkins Operator will make your life easier. After that, you can easily contribute to the project.
|
||||
{{% /blocks/feature %}}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ make go-dependencies
|
|||
Build and run **Jenkins Operator** locally:
|
||||
|
||||
```bash
|
||||
make minikube-run EXTRA_ARGS='--minikube --local'
|
||||
make build minikube-run EXTRA_ARGS='--minikube --local'
|
||||
```
|
||||
|
||||
Once minikube and **Jenkins Operator** are up and running, apply Jenkins custom resource:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: "v0.2.0"
|
||||
linkTitle: "v0.2.0"
|
||||
title: "Latest (v0.2.x)"
|
||||
linkTitle: "Latest (v0.2.x)"
|
||||
weight: 10
|
||||
date: 2019-08-05
|
||||
description: >
|
||||
|
|
@ -8,7 +8,7 @@ description: >
|
|||
---
|
||||
|
||||
{{% pageinfo %}}
|
||||
This document describes a getting started guide for **Jenkins Operator** `v0.2.0` and an additional configuration.
|
||||
This document describes a getting started guide for **Jenkins Operator** `v0.2.x` and an additional configuration.
|
||||
{{% /pageinfo %}}
|
||||
|
||||
## First Steps
|
||||
|
|
@ -49,7 +49,7 @@ pipelineJob('build-jenkins-operator') {
|
|||
}
|
||||
```
|
||||
|
||||
**cicd/jobs/build.jenkins** is an actual Jenkins pipeline:
|
||||
**cicd/pipelines/build.jenkins** is an actual Jenkins pipeline:
|
||||
|
||||
```
|
||||
#!/usr/bin/env groovy
|
||||
|
|
@ -1,4 +1,11 @@
|
|||
# Custom Backup and Restore Providers
|
||||
---
|
||||
title: "Custom Backup and Restore Providers"
|
||||
linkTitle: "Custom Backup and Restore Providers"
|
||||
weight: 10
|
||||
date: 2019-08-05
|
||||
description: >
|
||||
Custom backup and restore provider
|
||||
---
|
||||
|
||||
With enough effort one can create a custom backup and restore provider
|
||||
for the Jenkins Operator.
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
---
|
||||
title: "Migration from v0.1.1"
|
||||
linkTitle: "Migration from v0.1.1"
|
||||
title: "Migration from v0.1.x"
|
||||
linkTitle: "Migration from v0.1.x"
|
||||
weight: 10
|
||||
date: 2019-08-05
|
||||
description: >
|
||||
How to migrate from v0.1.1 to v0.2.0
|
||||
How to migrate from v0.1.x to v0.2.x
|
||||
---
|
||||
|
||||
### Added seed job agent
|
||||
|
|
@ -25,9 +25,13 @@ spec:
|
|||
configurationAsCode:
|
||||
configurations:
|
||||
- name: jenkins-operator-user-configuration-<cr_name>
|
||||
secret:
|
||||
name: jenkins-operator-user-configuration-<cr_name>
|
||||
groovyScripts:
|
||||
configurations:
|
||||
- name: jenkins-operator-user-configuration-<cr_name>
|
||||
secret:
|
||||
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**.
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
title: "v0.1.1"
|
||||
linkTitle: "v0.1.1"
|
||||
title: "v0.1.x"
|
||||
linkTitle: "v0.1.x"
|
||||
weight: 10
|
||||
date: 2019-08-05
|
||||
description: >
|
||||
|
|
@ -8,7 +8,7 @@ description: >
|
|||
---
|
||||
|
||||
{{% pageinfo %}}
|
||||
This document describes a getting started guide for **Jenkins Operator** `v0.1.1` and an additional configuration.
|
||||
This document describes a getting started guide for **Jenkins Operator** `v0.1.x` and an additional configuration.
|
||||
{{% /pageinfo %}}
|
||||
|
||||
## First Steps
|
||||
|
|
@ -47,7 +47,7 @@ pipelineJob('build-jenkins-operator') {
|
|||
}
|
||||
```
|
||||
|
||||
**cicd/jobs/build.jenkins** is an actual Jenkins pipeline:
|
||||
**cicd/pipelines/build.jenkins** is an actual Jenkins pipeline:
|
||||
|
||||
```
|
||||
#!/usr/bin/env groovy
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="{{ .Site.Language.Lang }}" class="no-js">
|
||||
<head>
|
||||
{{ partial "head.html" . }}
|
||||
<title>{{ if .IsHome }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{ . }} | {{ end }}{{ .Site.Title }}{{ end }}</title>
|
||||
</head>
|
||||
<body class="td-{{ .Kind }}">
|
||||
<header>
|
||||
{{ partial "navbar.html" . }}
|
||||
</header>
|
||||
<div class="container-fluid td-outer">
|
||||
<div class="td-main">
|
||||
<div class="row flex-xl-nowrap">
|
||||
<div class="col-12 col-md-3 col-xl-2 td-sidebar d-print-none">
|
||||
{{ partial "sidebar.html" . }}
|
||||
</div>
|
||||
<main class="col-12 col-md-9 col-xl-10 pl-md-5" role="main">
|
||||
{{ if not .Site.Params.ui.breadcrumb_disable }}{{ partial "breadcrumb.html" . }}{{ end }}
|
||||
{{ block "main" . }}{{ end }}
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
{{ partial "footer.html" . }}
|
||||
</div>
|
||||
{{ partial "scripts.html" . }}
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue