kubernetes-operator/pkg/controller/jenkins/configuration/base/resources/pod.go

262 lines
8.0 KiB
Go

package resources
import (
"fmt"
"github.com/jenkinsci/kubernetes-operator/pkg/apis/jenkinsio/v1alpha1"
"github.com/jenkinsci/kubernetes-operator/pkg/controller/jenkins/constants"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
const (
// JenkinsMasterContainerName is the Jenkins master container name in pod
JenkinsMasterContainerName = "jenkins-master"
jenkinsHomeVolumeName = "home"
jenkinsPath = "/var/jenkins"
jenkinsHomePath = jenkinsPath + "/home"
jenkinsScriptsVolumeName = "scripts"
jenkinsScriptsVolumePath = jenkinsPath + "/scripts"
initScriptName = "init.sh"
jenkinsOperatorCredentialsVolumeName = "operator-credentials"
jenkinsOperatorCredentialsVolumePath = jenkinsPath + "/operator-credentials"
jenkinsInitConfigurationVolumeName = "init-configuration"
jenkinsInitConfigurationVolumePath = jenkinsPath + "/init-configuration"
jenkinsBaseConfigurationVolumeName = "base-configuration"
// JenkinsBaseConfigurationVolumePath is a path where are groovy scripts used to configure Jenkins
// this scripts are provided by jenkins-operator
JenkinsBaseConfigurationVolumePath = jenkinsPath + "/base-configuration"
jenkinsUserConfigurationVolumeName = "user-configuration"
// JenkinsUserConfigurationVolumePath is a path where are groovy scripts and CasC configs used to configure Jenkins
// this script is provided by user
JenkinsUserConfigurationVolumePath = jenkinsPath + "/user-configuration"
userConfigurationSecretVolumeName = "user-configuration-secrets"
// UserConfigurationSecretVolumePath is a path where are secrets used for groovy scripts and CasC configs
UserConfigurationSecretVolumePath = jenkinsPath + "/user-configuration-secrets"
httpPortName = "http"
slavePortName = "slavelistener"
// HTTPPortInt defines Jenkins master HTTP port
HTTPPortInt = 8080
jenkinsUserUID = int64(1000) // build in Docker image jenkins user UID
)
func buildPodTypeMeta() metav1.TypeMeta {
return metav1.TypeMeta{
Kind: "Pod",
APIVersion: "v1",
}
}
// GetJenkinsMasterPodBaseEnvs returns Jenkins master pod envs required by operator
func GetJenkinsMasterPodBaseEnvs() []corev1.EnvVar {
return []corev1.EnvVar{
{
Name: "JENKINS_HOME",
Value: jenkinsHomePath,
},
{
Name: "JAVA_OPTS",
Value: "-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -Djenkins.install.runSetupWizard=false -Djava.awt.headless=true",
},
{
Name: "SECRETS", // https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/demos/kubernetes-secrets/README.md
Value: UserConfigurationSecretVolumePath,
},
}
}
// NewJenkinsMasterContainer returns Jenkins master Kubernetes container
func NewJenkinsMasterContainer(jenkins *v1alpha1.Jenkins) corev1.Container {
envs := GetJenkinsMasterPodBaseEnvs()
envs = append(envs, jenkins.Spec.Master.Env...)
return corev1.Container{
Name: JenkinsMasterContainerName,
Image: jenkins.Spec.Master.Image,
ImagePullPolicy: jenkins.Spec.Master.ImagePullPolicy,
Command: []string{
"bash",
fmt.Sprintf("%s/%s", jenkinsScriptsVolumePath, initScriptName),
},
LivenessProbe: jenkins.Spec.Master.LivenessProbe,
ReadinessProbe: jenkins.Spec.Master.ReadinessProbe,
Ports: []corev1.ContainerPort{
{
Name: httpPortName,
ContainerPort: constants.DefaultHTTPPortInt32,
Protocol: corev1.ProtocolTCP,
},
{
Name: slavePortName,
ContainerPort: constants.DefaultSlavePortInt32,
Protocol: corev1.ProtocolTCP,
},
},
Env: envs,
Resources: jenkins.Spec.Master.Resources,
VolumeMounts: []corev1.VolumeMount{
{
Name: jenkinsHomeVolumeName,
MountPath: jenkinsHomePath,
ReadOnly: false,
},
{
Name: jenkinsScriptsVolumeName,
MountPath: jenkinsScriptsVolumePath,
ReadOnly: true,
},
{
Name: jenkinsInitConfigurationVolumeName,
MountPath: jenkinsInitConfigurationVolumePath,
ReadOnly: true,
},
{
Name: jenkinsBaseConfigurationVolumeName,
MountPath: JenkinsBaseConfigurationVolumePath,
ReadOnly: true,
},
{
Name: jenkinsUserConfigurationVolumeName,
MountPath: JenkinsUserConfigurationVolumePath,
ReadOnly: true,
},
{
Name: jenkinsOperatorCredentialsVolumeName,
MountPath: jenkinsOperatorCredentialsVolumePath,
ReadOnly: true,
},
{
Name: userConfigurationSecretVolumeName,
MountPath: UserConfigurationSecretVolumePath,
ReadOnly: true,
},
},
}
}
// ConvertJenkinsContainerToKubernetesContainer converts Jenkins container to Kubernetes container
func ConvertJenkinsContainerToKubernetesContainer(container v1alpha1.Container) corev1.Container {
return corev1.Container{
Name: container.Name,
Image: container.Image,
Command: container.Command,
Args: container.Args,
WorkingDir: container.WorkingDir,
Ports: container.Ports,
EnvFrom: container.EnvFrom,
Env: container.Env,
Resources: container.Resources,
VolumeMounts: container.VolumeMounts,
LivenessProbe: container.LivenessProbe,
ReadinessProbe: container.ReadinessProbe,
Lifecycle: container.Lifecycle,
ImagePullPolicy: container.ImagePullPolicy,
SecurityContext: container.SecurityContext,
}
}
func newContainers(jenkins *v1alpha1.Jenkins) (containers []corev1.Container) {
containers = append(containers, NewJenkinsMasterContainer(jenkins))
for _, container := range jenkins.Spec.Master.Containers {
containers = append(containers, ConvertJenkinsContainerToKubernetesContainer(container))
}
return
}
// NewJenkinsMasterPod builds Jenkins Master Kubernetes Pod resource
func NewJenkinsMasterPod(objectMeta metav1.ObjectMeta, jenkins *v1alpha1.Jenkins) *corev1.Pod {
runAsUser := jenkinsUserUID
objectMeta.Annotations = jenkins.Spec.Master.Annotations
return &corev1.Pod{
TypeMeta: buildPodTypeMeta(),
ObjectMeta: objectMeta,
Spec: corev1.PodSpec{
ServiceAccountName: objectMeta.Name,
RestartPolicy: corev1.RestartPolicyNever,
SecurityContext: &corev1.PodSecurityContext{
RunAsUser: &runAsUser,
RunAsGroup: &runAsUser,
},
NodeSelector: jenkins.Spec.Master.NodeSelector,
Containers: newContainers(jenkins),
Volumes: []corev1.Volume{
{
Name: jenkinsHomeVolumeName,
VolumeSource: corev1.VolumeSource{
EmptyDir: &corev1.EmptyDirVolumeSource{},
},
},
{
Name: jenkinsScriptsVolumeName,
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: getScriptsConfigMapName(jenkins),
},
},
},
},
{
Name: jenkinsInitConfigurationVolumeName,
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: GetInitConfigurationConfigMapName(jenkins),
},
},
},
},
{
Name: jenkinsBaseConfigurationVolumeName,
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: GetBaseConfigurationConfigMapName(jenkins),
},
},
},
},
{
Name: jenkinsUserConfigurationVolumeName,
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: GetUserConfigurationConfigMapNameFromJenkins(jenkins),
},
},
},
},
{
Name: jenkinsOperatorCredentialsVolumeName,
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: GetOperatorCredentialsSecretName(jenkins),
},
},
},
{
Name: userConfigurationSecretVolumeName,
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: GetUserConfigurationSecretNameFromJenkins(jenkins),
},
},
},
},
},
}
}