Separate namespaces for Jenkins and Operator

How to install Jenkins and Jenkins Operator in separate namespaces

Create namespaces

You need to create two namespaces, for example we’ll call them jenkins for Jenkins and jenkins-operator for Jenkins Operator.

$ kubectl create ns jenkins-operator
$ kubectl create ns jenkins

Create necessary resources in Jenkins Operator namespace

Next, you need to install resources necessary for the Operator to work in the jenkins-operator namespace. To do that, copy the manifest you see below to jenkins-operator-rbac.yamlfile.

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins-operator
---
# permissions to do leader election.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: leader-election-role
rules:
- apiGroups:
  - ""
  - coordination.k8s.io
  resources:
  - configmaps
  - leases
  verbs:
  - get
  - list
  - watch
  - create
  - update
  - patch
  - delete
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: leader-election-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: leader-election-role
subjects:
- kind: ServiceAccount
  name: jenkins-operator
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: jenkins-operator
rules:
- apiGroups:
  - apps
  resources:
  - daemonsets
  - deployments
  - replicasets
  - statefulsets
  verbs:
  - '*'
- apiGroups:
  - apps
  - jenkins-operator
  resources:
  - deployments/finalizers
  verbs:
  - update
- apiGroups:
  - build.openshift.io
  resources:
  - buildconfigs
  - builds
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - configmaps
  - secrets
  - services
  verbs:
  - create
  - get
  - list
  - update
  - watch
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - create
  - get
  - list
  - patch
  - watch
- apiGroups:
  - ""
  resources:
  - persistentvolumeclaims
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - ""
  resources:
  - pods
  - pods/exec
  verbs:
  - '*'
- apiGroups:
  - ""
  resources:
  - pods/log
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - pods/portforward
  verbs:
  - create
- apiGroups:
  - ""
  resources:
  - serviceaccounts
  verbs:
  - create
  - get
  - list
  - update
  - watch
- apiGroups:
  - image.openshift.io
  resources:
  - imagestreams
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - jenkins.io
  resources:
  - '*'
  verbs:
  - '*'
- apiGroups:
  - jenkins.io
  resources:
  - jenkins
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - jenkins.io
  resources:
  - jenkins/finalizers
  verbs:
  - update
- apiGroups:
  - jenkins.io
  resources:
  - jenkins/status
  verbs:
  - get
  - patch
  - update
- apiGroups:
  - rbac.authorization.k8s.io
  resources:
  - rolebindings
  - roles
  verbs:
  - create
  - get
  - list
  - update
  - watch
- apiGroups:
  - route.openshift.io
  resources:
  - routes
  verbs:
  - create
  - get
  - list
  - update
  - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: jenkins-operator
subjects:
  - kind: ServiceAccount
    name: jenkins-operator
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: jenkins-operator

Now install the required resources in jenkins-operator namespace with:

kubectl apply -n jenkins-operator -f jenkins-operator-rbac.yaml

There’s only one thing left to install in jenkins-operator namespace, and that is the Operator itself. The manifest below contains the Operator as defined in all-in-one manifest found in Installing the Operator page, the only difference is that the one here sets WATCH_NAMESPACE to the jenkins namespace we created.

Copy its content to jenkins-operator.yaml file.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: jenkins-operator
  labels:
    control-plane: controller-manager
spec:
  selector:
    matchLabels:
      control-plane: controller-manager
  replicas: 1
  template:
    metadata:
      labels:
        control-plane: controller-manager
    spec:
      serviceAccountName: jenkins-operator
      securityContext:
        runAsUser: 65532
      containers:
        - command:
            - /manager
          args:
            - --leader-elect
          image: virtuslab/jenkins-operator:v0.6.0
          name: jenkins-operator
          imagePullPolicy: IfNotPresent
          securityContext:
            allowPrivilegeEscalation: false
          livenessProbe:
            httpGet:
              path: /healthz
              port: 8081
            initialDelaySeconds: 15
            periodSeconds: 20
          readinessProbe:
            httpGet:
              path: /readyz
              port: 8081
            initialDelaySeconds: 5
            periodSeconds: 10
          resources:
            limits:
              cpu: 100m
              memory: 30Mi
            requests:
              cpu: 100m
              memory: 20Mi
          env:
            - name: WATCH_NAMESPACE
              value: jenkins
      terminationGracePeriodSeconds: 10

Install the Operator in jenkins-operator namespace with:

kubectl apply -n jenkins-operator -f jenkins-operator.yaml

You have installed the Operator in jenkins-operator namespace, watching for Jenkins in jenkins namespace. Now there are two things left to do: creating necessary Role and RoleBinding for the Operator in jenkins namespace, and deploying actual Jenkins instance there.

Create necessary resources in Jenkins namespace

Below you can find manifest with RBAC that needs to be created in jenkins namespace. Copy its content to jenkins-ns-rbac.yaml file.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: jenkins-operator
rules:
  - apiGroups:
      - apps
    resources:
      - daemonsets
      - deployments
      - replicasets
      - statefulsets
    verbs:
      - '*'
  - apiGroups:
      - apps
      - jenkins-operator
    resources:
      - deployments/finalizers
    verbs:
      - update
  - apiGroups:
      - build.openshift.io
    resources:
      - buildconfigs
      - builds
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - configmaps
      - secrets
      - services
    verbs:
      - create
      - get
      - list
      - update
      - watch
  - apiGroups:
      - ""
    resources:
      - events
    verbs:
      - create
      - get
      - list
      - patch
      - watch
  - apiGroups:
      - ""
    resources:
      - persistentvolumeclaims
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - pods
    verbs:
      - create
      - delete
      - get
      - list
      - patch
      - update
      - watch
  - apiGroups:
      - ""
    resources:
      - pods
      - pods/exec
    verbs:
      - '*'
  - apiGroups:
      - ""
    resources:
      - pods/log
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - ""
    resources:
      - pods/portforward
    verbs:
      - create
  - apiGroups:
      - ""
    resources:
      - serviceaccounts
    verbs:
      - create
      - get
      - list
      - update
      - watch
  - apiGroups:
      - image.openshift.io
    resources:
      - imagestreams
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - jenkins.io
    resources:
      - '*'
    verbs:
      - '*'
  - apiGroups:
      - jenkins.io
    resources:
      - jenkins
    verbs:
      - create
      - delete
      - get
      - list
      - patch
      - update
      - watch
  - apiGroups:
      - jenkins.io
    resources:
      - jenkins/finalizers
    verbs:
      - update
  - apiGroups:
      - jenkins.io
    resources:
      - jenkins/status
    verbs:
      - get
      - patch
      - update
  - apiGroups:
      - rbac.authorization.k8s.io
    resources:
      - rolebindings
      - roles
    verbs:
      - create
      - get
      - list
      - update
      - watch
  - apiGroups:
      - route.openshift.io
    resources:
      - routes
    verbs:
      - create
      - get
      - list
      - update
      - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: jenkins-operator
subjects:
  - kind: ServiceAccount
    name: jenkins-operator
    namespace: jenkins-operator
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: jenkins-operator

Now apply it with:

kubectl apply -n jenkins -f jenkins-ns-rbac.yaml

The last thing to do is to deploy Jenkins. Below you can find an example Jenkins resource manifest. It’s the same as one used in Deploying Jenkins. Copy it to jenkins-instance.yaml

apiVersion: jenkins.io/v1alpha2
kind: Jenkins
metadata:
  name: example
spec:
  configurationAsCode:
    configurations: []
    secret:
      name: ""
  groovyScripts:
    configurations: []
    secret:
      name: ""
  jenkinsAPISettings:
    authorizationStrategy: createUser
  master:
    disableCSRFProtection: false
    containers:
      - name: jenkins-master
        image: jenkins/jenkins:2.277.4-lts-alpine
        imagePullPolicy: Always
        livenessProbe:
          failureThreshold: 12
          httpGet:
            path: /login
            port: http
            scheme: HTTP
          initialDelaySeconds: 100
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 5
        readinessProbe:
          failureThreshold: 10
          httpGet:
            path: /login
            port: http
            scheme: HTTP
          initialDelaySeconds: 80
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        resources:
          limits:
            cpu: 1500m
            memory: 3Gi
          requests:
            cpu: "1"
            memory: 500Mi
  seedJobs:
    - id: jenkins-operator
      targets: "cicd/jobs/*.jenkins"
      description: "Jenkins Operator repository"
      repositoryBranch: master
      repositoryUrl: https://github.com/jenkinsci/kubernetes-operator.git

Now you can deploy it with:

kubectl apply -n jenkins -f jenkins-instance.yaml

With this, you have just set up Jenkins Operator and Jenkins in separate namespaces. Now the Operator will run in its own namespace (jenkins-operator), watch for CRs in jenkins namespace, and deploy Jenkins there.

Last modified October 6, 2021