Merge pull request #353 from akram/0.4-openshift-docs
Adding OpenShift doc
This commit is contained in:
		
						commit
						55cfdf5687
					
				|  | @ -0,0 +1,8 @@ | ||||||
|  | KUBERNETES_PROVIDER=crc | ||||||
|  | DOCKER_ORGANIZATION=image-registry.openshift-image-registry.svc:5000/jenkins-operator | ||||||
|  | DOCKER_REGISTRY=kubernetes-operator | ||||||
|  | IMAGE_PULL_MODE=remote | ||||||
|  | JENKINS_API_PORT=0 | ||||||
|  | JENKINS_API_USE_NODEPORT=false | ||||||
|  | NAMESPACE=$(oc project -q) | ||||||
|  | 
 | ||||||
|  | @ -24,9 +24,9 @@ spec: | ||||||
|       - name: KUBERNETES_TRUST_CERTIFICATES |       - name: KUBERNETES_TRUST_CERTIFICATES | ||||||
|         value: 'true' |         value: 'true' | ||||||
|       - name: JENKINS_SERVICE_NAME |       - name: JENKINS_SERVICE_NAME | ||||||
|             value: jenkins-operator-http-example |         value: jenkins-operator-http-jenkins | ||||||
|       - name: JNLP_SERVICE_NAME |       - name: JNLP_SERVICE_NAME | ||||||
|             value: jenkins-operator-slave-example |         value: jenkins-operator-slave-jenkins | ||||||
|       - name: JENKINS_UC_INSECURE |       - name: JENKINS_UC_INSECURE | ||||||
|         value: 'false' |         value: 'false' | ||||||
|       - name: JENKINS_HOME |       - name: JENKINS_HOME | ||||||
|  | @ -67,4 +67,7 @@ spec: | ||||||
|   slaveService: |   slaveService: | ||||||
|     port: 50000 |     port: 50000 | ||||||
|     type: ClusterIP |     type: ClusterIP | ||||||
|  |   serviceAccount: | ||||||
|  |     annotations: | ||||||
|  |       serviceaccounts.openshift.io/oauth-redirectreference.jenkins: '{"kind":"OAuthRedirectReference","apiVersion":"v1","reference":{"kind":"Route","name":"jenkins-operator"}}' | ||||||
|      |      | ||||||
|  |  | ||||||
|  | @ -767,7 +767,12 @@ func TestEnsureExtraRBAC(t *testing.T) { | ||||||
| 				Roles: []rbacv1.RoleRef{}, | 				Roles: []rbacv1.RoleRef{}, | ||||||
| 			}, | 			}, | ||||||
| 		} | 		} | ||||||
| 		reconciler := New(configuration.Configuration{Client: fakeClient, Jenkins: jenkins, Scheme: scheme.Scheme}, nil, client.JenkinsAPIConnectionSettings{}) | 		config := configuration.Configuration{ | ||||||
|  | 			Client:  fakeClient, | ||||||
|  | 			Jenkins: jenkins, | ||||||
|  | 			Scheme:  scheme.Scheme, | ||||||
|  | 		} | ||||||
|  | 		reconciler := New(config, log.Log, client.JenkinsAPIConnectionSettings{}) | ||||||
| 		metaObject := resources.NewResourceObjectMeta(jenkins) | 		metaObject := resources.NewResourceObjectMeta(jenkins) | ||||||
| 
 | 
 | ||||||
| 		// when
 | 		// when
 | ||||||
|  | @ -803,7 +808,12 @@ func TestEnsureExtraRBAC(t *testing.T) { | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| 		} | 		} | ||||||
| 		reconciler := New(configuration.Configuration{Client: fakeClient, Jenkins: jenkins, Scheme: scheme.Scheme}, nil, client.JenkinsAPIConnectionSettings{}) | 		config := configuration.Configuration{ | ||||||
|  | 			Client:  fakeClient, | ||||||
|  | 			Jenkins: jenkins, | ||||||
|  | 			Scheme:  scheme.Scheme, | ||||||
|  | 		} | ||||||
|  | 		reconciler := New(config, log.Log, client.JenkinsAPIConnectionSettings{}) | ||||||
| 		metaObject := resources.NewResourceObjectMeta(jenkins) | 		metaObject := resources.NewResourceObjectMeta(jenkins) | ||||||
| 
 | 
 | ||||||
| 		// when
 | 		// when
 | ||||||
|  | @ -845,7 +855,12 @@ func TestEnsureExtraRBAC(t *testing.T) { | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| 		} | 		} | ||||||
| 		reconciler := New(configuration.Configuration{Client: fakeClient, Jenkins: jenkins, Scheme: scheme.Scheme}, nil, client.JenkinsAPIConnectionSettings{}) | 		config := configuration.Configuration{ | ||||||
|  | 			Client:  fakeClient, | ||||||
|  | 			Jenkins: jenkins, | ||||||
|  | 			Scheme:  scheme.Scheme, | ||||||
|  | 		} | ||||||
|  | 		reconciler := New(config, log.Log, client.JenkinsAPIConnectionSettings{}) | ||||||
| 		metaObject := resources.NewResourceObjectMeta(jenkins) | 		metaObject := resources.NewResourceObjectMeta(jenkins) | ||||||
| 
 | 
 | ||||||
| 		// when
 | 		// when
 | ||||||
|  | @ -888,7 +903,12 @@ func TestEnsureExtraRBAC(t *testing.T) { | ||||||
| 				}, | 				}, | ||||||
| 			}, | 			}, | ||||||
| 		} | 		} | ||||||
| 		reconciler := New(configuration.Configuration{Client: fakeClient, Jenkins: jenkins, Scheme: scheme.Scheme}, log.Log, client.JenkinsAPIConnectionSettings{}) | 		config := configuration.Configuration{ | ||||||
|  | 			Client:  fakeClient, | ||||||
|  | 			Jenkins: jenkins, | ||||||
|  | 			Scheme:  scheme.Scheme, | ||||||
|  | 		} | ||||||
|  | 		reconciler := New(config, log.Log, client.JenkinsAPIConnectionSettings{}) | ||||||
| 		metaObject := resources.NewResourceObjectMeta(jenkins) | 		metaObject := resources.NewResourceObjectMeta(jenkins) | ||||||
| 
 | 
 | ||||||
| 		// when
 | 		// when
 | ||||||
|  |  | ||||||
|  | @ -13,10 +13,12 @@ const ( | ||||||
| 	watchVerb  = "watch" | 	watchVerb  = "watch" | ||||||
| 	patchVerb  = "patch" | 	patchVerb  = "patch" | ||||||
| 	updateVerb = "update" | 	updateVerb = "update" | ||||||
| 	EmptyApiGroups    = "" | 	//EmptyAPIGroup short hand for the empty API group while defining policies
 | ||||||
| 	OpenshiftApiGroup = "image.openshift.io" | 	EmptyAPIGroup = "" | ||||||
| 	BuildApiGroup     = "build.openshift.io" | 	//OpenshiftAPIGroup the openshift api group name
 | ||||||
| 
 | 	OpenshiftAPIGroup = "image.openshift.io" | ||||||
|  | 	//BuildAPIGroup  the openshift api group name for builds
 | ||||||
|  | 	BuildAPIGroup = "build.openshift.io" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // NewRole returns rbac role for jenkins master
 | // NewRole returns rbac role for jenkins master
 | ||||||
|  | @ -54,22 +56,23 @@ func NewRoleBinding(name, namespace, serviceAccountName string, roleRef v1.RoleR | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // NewDefaultPolicyRules sets the default policy rules
 | ||||||
| func NewDefaultPolicyRules() []v1.PolicyRule { | func NewDefaultPolicyRules() []v1.PolicyRule { | ||||||
| 	var rules []v1.PolicyRule | 	var rules []v1.PolicyRule | ||||||
| 	ReadOnly := []string{getVerb, listVerb, watchVerb} | 	ReadOnly := []string{getVerb, listVerb, watchVerb} | ||||||
| 	Default := []string{createVerb, deleteVerb, getVerb, listVerb, patchVerb, updateVerb, watchVerb} | 	Default := []string{createVerb, deleteVerb, getVerb, listVerb, patchVerb, updateVerb, watchVerb} | ||||||
| 	Create := []string{createVerb} | 	Create := []string{createVerb} | ||||||
| 
 | 
 | ||||||
| 	rules = append(rules,  NewPolicyRule(EmptyApiGroups, "pods/portforward", Create)) | 	rules = append(rules, NewPolicyRule(EmptyAPIGroup, "pods/portforward", Create)) | ||||||
| 	rules = append(rules,  NewPolicyRule(EmptyApiGroups, "pods", Default)) | 	rules = append(rules, NewPolicyRule(EmptyAPIGroup, "pods", Default)) | ||||||
| 	rules = append(rules,  NewPolicyRule(EmptyApiGroups, "pods/exec", Default)) | 	rules = append(rules, NewPolicyRule(EmptyAPIGroup, "pods/exec", Default)) | ||||||
| 	rules = append(rules,  NewPolicyRule(EmptyApiGroups, "configmaps", ReadOnly)) | 	rules = append(rules, NewPolicyRule(EmptyAPIGroup, "configmaps", ReadOnly)) | ||||||
| 	rules = append(rules,  NewPolicyRule(EmptyApiGroups, "pods/log", ReadOnly)) | 	rules = append(rules, NewPolicyRule(EmptyAPIGroup, "pods/log", ReadOnly)) | ||||||
| 	rules = append(rules,  NewPolicyRule(EmptyApiGroups, "secrets", ReadOnly)) | 	rules = append(rules, NewPolicyRule(EmptyAPIGroup, "secrets", ReadOnly)) | ||||||
| 
 | 
 | ||||||
| 	rules = append(rules,  NewOpenShiftPolicyRule(OpenshiftApiGroup, "imagestreams", ReadOnly)) | 	rules = append(rules, NewOpenShiftPolicyRule(OpenshiftAPIGroup, "imagestreams", ReadOnly)) | ||||||
| 	rules = append(rules,  NewOpenShiftPolicyRule(BuildApiGroup, "buildconfigs", ReadOnly)) | 	rules = append(rules, NewOpenShiftPolicyRule(BuildAPIGroup, "buildconfigs", ReadOnly)) | ||||||
| 	rules = append(rules,  NewOpenShiftPolicyRule(BuildApiGroup, "builds", ReadOnly)) | 	rules = append(rules, NewOpenShiftPolicyRule(BuildAPIGroup, "builds", ReadOnly)) | ||||||
| 
 | 
 | ||||||
| 	return rules | 	return rules | ||||||
| } | } | ||||||
|  | @ -84,8 +87,7 @@ func NewPolicyRule(apiGroup string, resource string, verbs []string) v1.PolicyRu | ||||||
| 	return rule | 	return rule | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewPolicyRule returns a policyRule allowing verbs on resources
 | // NewOpenShiftPolicyRule returns a policyRule allowing verbs on resources
 | ||||||
| func NewOpenShiftPolicyRule(apiGroup string, resource string, verbs []string) v1.PolicyRule { | func NewOpenShiftPolicyRule(apiGroup string, resource string, verbs []string) v1.PolicyRule { | ||||||
| 	return NewPolicyRule(apiGroup, resource, verbs) | 	return NewPolicyRule(apiGroup, resource, verbs) | ||||||
| } | } | ||||||
| 
 |  | ||||||
|  |  | ||||||
|  | @ -2,8 +2,10 @@ package base | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
|  | 	"fmt" | ||||||
| 
 | 
 | ||||||
| 	"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources" | 	"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/configuration/base/resources" | ||||||
|  | 	"github.com/jenkinsci/kubernetes-operator/pkg/log" | ||||||
| 
 | 
 | ||||||
| 	stackerr "github.com/pkg/errors" | 	stackerr "github.com/pkg/errors" | ||||||
| 	corev1 "k8s.io/api/core/v1" | 	corev1 "k8s.io/api/core/v1" | ||||||
|  | @ -15,8 +17,11 @@ import ( | ||||||
| func (r *ReconcileJenkinsBaseConfiguration) createServiceAccount(meta metav1.ObjectMeta) error { | func (r *ReconcileJenkinsBaseConfiguration) createServiceAccount(meta metav1.ObjectMeta) error { | ||||||
| 	serviceAccount := &corev1.ServiceAccount{} | 	serviceAccount := &corev1.ServiceAccount{} | ||||||
| 	err := r.Client.Get(context.TODO(), types.NamespacedName{Name: meta.Name, Namespace: meta.Namespace}, serviceAccount) | 	err := r.Client.Get(context.TODO(), types.NamespacedName{Name: meta.Name, Namespace: meta.Namespace}, serviceAccount) | ||||||
|  | 	annotations := r.Configuration.Jenkins.Spec.ServiceAccount.Annotations | ||||||
|  | 	msg := fmt.Sprintf("createServiceAccount with annotations %v", annotations) | ||||||
|  | 	r.logger.V(log.VDebug).Info(msg) | ||||||
| 	if err != nil && apierrors.IsNotFound(err) { | 	if err != nil && apierrors.IsNotFound(err) { | ||||||
| 		serviceAccount = resources.NewServiceAccount(meta, r.Configuration.Jenkins.Spec.ServiceAccount.Annotations) | 		serviceAccount = resources.NewServiceAccount(meta, annotations) | ||||||
| 		if err = r.CreateResource(serviceAccount); err != nil { | 		if err = r.CreateResource(serviceAccount); err != nil { | ||||||
| 			return stackerr.WithStack(err) | 			return stackerr.WithStack(err) | ||||||
| 		} | 		} | ||||||
|  | @ -24,11 +29,11 @@ func (r *ReconcileJenkinsBaseConfiguration) createServiceAccount(meta metav1.Obj | ||||||
| 		return stackerr.WithStack(err) | 		return stackerr.WithStack(err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if !compareMap(r.Configuration.Jenkins.Spec.ServiceAccount.Annotations, serviceAccount.Annotations) { | 	if !compareMap(annotations, serviceAccount.Annotations) { | ||||||
| 		if serviceAccount.Annotations == nil { | 		if serviceAccount.Annotations == nil { | ||||||
| 			serviceAccount.Annotations = map[string]string{} | 			serviceAccount.Annotations = map[string]string{} | ||||||
| 		} | 		} | ||||||
| 		for key, value := range r.Configuration.Jenkins.Spec.ServiceAccount.Annotations { | 		for key, value := range annotations { | ||||||
| 			serviceAccount.Annotations[key] = value | 			serviceAccount.Annotations[key] = value | ||||||
| 		} | 		} | ||||||
| 		if err = r.UpdateResource(serviceAccount); err != nil { | 		if err = r.UpdateResource(serviceAccount); err != nil { | ||||||
|  |  | ||||||
|  | @ -0,0 +1,104 @@ | ||||||
|  | --- | ||||||
|  | title: "OpenShift" | ||||||
|  | linkTitle: "OpenShift" | ||||||
|  | weight: 20 | ||||||
|  | date: 2020-04-29 | ||||||
|  | description: > | ||||||
|  |     Additional configuration for OpenShift | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | ## SecurityContext | ||||||
|  | 
 | ||||||
|  | OpenShift enforces Security Constraints Context (scc) when deploying an image. | ||||||
|  | By default, container images run in restricted scc which prevents from setting | ||||||
|  | a fixed user id to run with. You need to have ensure that you do not provide a | ||||||
|  | securityContext with a runAsUser and that your image does not use a hardcoded user. | ||||||
|  | 
 | ||||||
|  | ```yaml | ||||||
|  | securityContext: {} | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## OpenShift Jenkins image | ||||||
|  | 
 | ||||||
|  | OpenShift provides a pre-configured Jenkins image containing  3 openshift plugins for | ||||||
|  | jenkins (openshift-login-plugin, openshift-sync-plugin and openshift-client-plugin) | ||||||
|  | which allows better jenkins integration with kubernetes and OpenShift. | ||||||
|  | 
 | ||||||
|  | The OpenShift Jenkins image requires additional configuration to be fully enabled. | ||||||
|  | 
 | ||||||
|  | ### Sample OpenShift CR | ||||||
|  | The following Custom Resource can be used to create a Jenkins instance using the   | ||||||
|  | OpenShift Jenkins image and sets values for: | ||||||
|  | - `image: 'quay.io/openshift/origin-jenkins:latest' : This is the OpenShift Jenkins image. | ||||||
|  | 
 | ||||||
|  | - serviceAccount: to allow oauth authentication to work, the service account needs | ||||||
|  | a specific annotation pointing to the route exposing the jenkins service. Here, | ||||||
|  | the route is named `jenkins-route` | ||||||
|  | 
 | ||||||
|  | - `OPENSHIFT_ENABLE_OAUTH` environment variable for the master container is set to true. | ||||||
|  | 
 | ||||||
|  | Here is a complete Jenkins CR allowing the deployment of the Jenkins OpenShift image. | ||||||
|  | ```yaml | ||||||
|  | apiVersion: jenkins.io/v1alpha2 | ||||||
|  | kind: Jenkins | ||||||
|  | metadata: | ||||||
|  |   annotations: | ||||||
|  |     jenkins.io/openshift-mode: 'true' | ||||||
|  |   name: jenkins | ||||||
|  | spec: | ||||||
|  |   serviceAccount: | ||||||
|  |     annotations: | ||||||
|  |       serviceaccounts.openshift.io/oauth-redirectreference.jenkins: '{"kind":"OAuthRedirectReference","apiVersion":"v1","reference":{"kind":"Route","name":"jenkins-route"}}' | ||||||
|  |   master: | ||||||
|  |     containers: | ||||||
|  |     - name: jenkins-master | ||||||
|  |       image: 'quay.io/openshift/origin-jenkins:latest' | ||||||
|  |       command: | ||||||
|  |       - /usr/bin/go-init | ||||||
|  |       - '-main' | ||||||
|  |       - /usr/libexec/s2i/run | ||||||
|  |       env: | ||||||
|  |       - name: OPENSHIFT_ENABLE_OAUTH | ||||||
|  |         value: 'true' | ||||||
|  |       - name: OPENSHIFT_ENABLE_REDIRECT_PROMPT | ||||||
|  |         value: 'true' | ||||||
|  |       - name: DISABLE_ADMINISTRATIVE_MONITORS | ||||||
|  |         value: 'false' | ||||||
|  |       - name: KUBERNETES_MASTER | ||||||
|  |         value: 'https://kubernetes.default:443' | ||||||
|  |       - name: KUBERNETES_TRUST_CERTIFICATES | ||||||
|  |         value: 'true' | ||||||
|  |       - name: JENKINS_SERVICE_NAME | ||||||
|  |         value: jenkins-operator-http-jenkins | ||||||
|  |       - name: JNLP_SERVICE_NAME | ||||||
|  |         value: jenkins-operator-slave-jenkins | ||||||
|  |       - name: JENKINS_UC_INSECURE | ||||||
|  |         value: 'false' | ||||||
|  |       - name: JENKINS_HOME | ||||||
|  |         value: /var/lib/jenkins | ||||||
|  |       - name: JAVA_OPTS | ||||||
|  |         value: >- | ||||||
|  |           -XX:+UnlockExperimentalVMOptions -XX:+UnlockExperimentalVMOptions | ||||||
|  |           -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 | ||||||
|  |           -Djenkins.install.runSetupWizard=false -Djava.awt.headless=true | ||||||
|  |       imagePullPolicy: Always | ||||||
|  |   service: | ||||||
|  |     port: 8080 | ||||||
|  |     type: ClusterIP | ||||||
|  |   slaveService: | ||||||
|  |     port: 50000 | ||||||
|  |     type: ClusterIP | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### OpenShift OAuth integration | ||||||
|  | The creation of a Route is required for the integraiton of Jenkins with | ||||||
|  | OpenShift oauth authentication. By default, the jenkins http service is named | ||||||
|  | `jenkins-operator-http-${jenkins-cr-name}` | ||||||
|  | 
 | ||||||
|  | ```bash | ||||||
|  | oc create route edge jenkins-route --service=jenkins-operator-http-jenkins | ||||||
|  | ``` | ||||||
|  | Note: the route name (jenkins-route) must match the pointed route on the serviceaccount annotation. | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | After the creation of the Route. It can be used to navigate to the Jenkins Login Page and login with your Openshift Credentials. | ||||||
		Loading…
	
		Reference in New Issue