* initial commit

* Jenkins chart

* Move jenkins to incubator

* Update chart metadata

* Optimize image layers

* Update Jenkins readme

* Use fullname template where possible

* Templatize configmap name

* Add icon to chart metadata

* Add configurable JAVA_OPTS

* Add NOTES.txt explaining next steps

* Update to support namespaces

* Update tests

* Update test image
This commit is contained in:
Vic Iglesias
2016-09-12 12:01:29 -07:00
committed by GitHub
parent b8a64da78f
commit a784b17138
15 changed files with 430 additions and 5 deletions
+21
View File
@@ -0,0 +1,21 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
+13
View File
@@ -0,0 +1,13 @@
name: jenkins
home: https://jenkins.io/
version: 0.1.0
description: A Jenkins Helm chart for Kubernetes.
sources:
- https://github.com/jenkinsci/jenkins
- https://github.com/jenkinsci/docker-jnlp-slave
maintainers:
- name: Lachlan Evenson
email: lachlan@deis.com
- name: Vic Iglesias
email: viglesias@google.com
icon: https://wiki.jenkins-ci.org/download/attachments/2916393/logo.png
+77
View File
@@ -0,0 +1,77 @@
# Jenkins Helm Chart
Jenkins master and slave cluster utilizing the Jenkins Kubernetes plugin
* https://wiki.jenkins-ci.org/display/JENKINS/Kubernetes+Plugin
Inspired by the awesome work of Carlos Sanchez <carlos@apache.org>
## Chart Details
This chart will do the following:
* 1 x Jenkins Master with port 8080 exposed on an external LoadBalancer
* All using Kubernetes Deployments
## Get this chart
Download the latest release of the chart from the [releases](../../../releases) page.
Alternatively, clone the repo if you wish to use the development snapshot:
```bash
$ git clone https://github.com/kubernetes/charts.git
```
## Installing the Chart
To install the chart with the release name `my-release`:
```bash
$ helm install --name my-release jenkins-x.x.x.tgz
```
## Configuration
The following tables lists the configurable parameters of the Jenkins chart and their default values.
### Jenkins Master
| Parameter | Description | Default |
|-----------------------|----------------------------------|----------------------------------------------------------|
| `Master.Name` | Jenkins master name | `jenkins-master` |
| `Master.Image` | Master image name | `gcr.io/kubernetes-charts-ci/jenkins-master-k8s` |
| `Master.ImageTag` | Master image tag | `v0.1.0` |
| `Master.ImagePullPolicy` | Master image pull policy | `Always` |
| `Master.Component` | k8s selector key | `jenkins-master` |
| `Master.Cpu` | Master requested cpu | `200m` |
| `Master.Memory` | Master requested memory | `256Mi` |
| `Master.ServicePort` | k8s service port | `8080` |
| `Master.ContainerPort`| Master listening port | `8080` |
| `Master.SlaveListenerPort`| Listening port for agents | `50000` |
### Jenkins Agent
| Parameter | Description | Default |
|-----------------------|----------------------------------|----------------------------------------------------------|
| `Agent.Image` | Agent image name | `jenkinsci/jnlp-slave` |
| `Agent.ImageTag` | Agent image tag | `2.52` | |
| `Agent.Cpu` | Agent requested cpu | `200m` |
| `Agent.Memory` | Agent requested memory | `256Mi` |
Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`.
Alternatively, a YAML file that specifies the values for the parameters can be provided while installing the chart. For example,
```bash
$ helm install --name my-release -f values.yaml jenkins-x.x.x.tgz
```
> **Tip**: You can use the default [values.yaml](values.yaml)
## Persistence
The Jenkins image stores persistence under `/var/jenkins_home` path of the container. A Persistent Volume
Claim is used to keep the data across deployments. This is known to work in GCE, AWS, and minikube.
# Todo
* Enable Docker-in-Docker or Docker-on-Docker support on the Jenkins agents
@@ -0,0 +1,4 @@
FROM jenkins:2.7.3
RUN /usr/local/bin/install-plugins.sh kubernetes:0.8 workflow-aggregator:2.3 \
&& mkdir -p /usr/share/jenkins/ref/secrets/ \
&& echo "false" > /usr/share/jenkins/ref/secrets/slave-to-master-security-kill-switch
+36
View File
@@ -0,0 +1,36 @@
Getting Started:
1. Get your '{{ .Values.Master.AdminUser }}' user password by running:
printf $(printf '\%o' `kubectl get secret --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath="{.data.jenkins-admin-password[*]}"`);echo
2. Get the Jenkins URL to visit by running these commands in the same shell:
{{- if contains "NodePort" .Values.Master.ServiceType }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT/login
{{- else if contains "LoadBalancer" .Values.Master.ServiceType }}
**** NOTE: It may take a few minutes for the LoadBalancer IP to be available. ****
**** You can watch the status of by running 'kubectl get svc -w {{ template "fullname" . }}' ****
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.Master.ServicePort }}/login
{{- else if contains "ClusterIP" .Values.Master.ServiceType }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "component={{ template "fullname" . }}-master" -o jsonpath="{.items[0].metadata.name}")
echo http://127.0.0.1:{{ .Values.Master.ServicePort }}
kubectl port-forward $POD_NAME {{ .Values.Master.ServicePort }}:{{ .Values.Master.ServicePort }}
{{- end }}
3. Login with the password from step 1 and the username: {{ .Values.Master.AdminUser }}
For more information on running Jenkins on Kubernetes, visit:
https://cloud.google.com/solutions/jenkins-on-container-engine
{{- if .Values.Persistence.Enabled }}
{{- else }}
#################################################################################
###### WARNING: Persistence is disabled!!! You will lose your data when #####
###### the Jenkins pod is terminated. #####
#################################################################################
{{- end }}
+16
View File
@@ -0,0 +1,16 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 24 -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 24 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "fullname" -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- printf "%s-%s" .Release.Name $name | trunc 24 -}}
{{- end -}}
+77
View File
@@ -0,0 +1,77 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "fullname" . }}
data:
config.xml: |-
<?xml version='1.0' encoding='UTF-8'?>
<hudson>
<disabledAdministrativeMonitors/>
<version>2.7.3</version>
<numExecutors>0</numExecutors>
<mode>NORMAL</mode>
<useSecurity>true</useSecurity>
<authorizationStrategy class="hudson.security.FullControlOnceLoggedInAuthorizationStrategy">
<denyAnonymousReadAccess>true</denyAnonymousReadAccess>
</authorizationStrategy>
<securityRealm class="hudson.security.LegacySecurityRealm"/>
<disableRememberMe>false</disableRememberMe>
<projectNamingStrategy class="jenkins.model.ProjectNamingStrategy$DefaultProjectNamingStrategy"/>
<workspaceDir>${JENKINS_HOME}/workspace/${ITEM_FULLNAME}</workspaceDir>
<buildsDir>${ITEM_ROOTDIR}/builds</buildsDir>
<markupFormatter class="hudson.markup.EscapedMarkupFormatter"/>
<jdks/>
<viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
<myViewsTabBar class="hudson.views.DefaultMyViewsTabBar"/>
<clouds>
<org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud plugin="kubernetes@0.8">
<name>default</name>
<templates>
<org.csanchez.jenkins.plugins.kubernetes.PodTemplate>
<name>default</name>
<image>{{ .Values.Agent.Image }}:{{ .Values.Agent.ImageTag }}</image>
<privileged>false</privileged>
<alwaysPullImage>false</alwaysPullImage>
<command></command>
<args></args>
<remoteFs>/home/jenkins</remoteFs>
<instanceCap>2147483647</instanceCap>
<label></label>
<nodeSelector></nodeSelector>
<resourceRequestCpu>{{.Values.Agent.Cpu}}</resourceRequestCpu>
<resourceRequestMemory>{{.Values.Agent.Memory}}</resourceRequestMemory>
<resourceLimitCpu>{{.Values.Agent.Cpu}}</resourceLimitCpu>
<resourceLimitMemory>{{.Values.Agent.Memory}}</resourceLimitMemory>
<volumes/>
<envVars/>
<annotations/>
<imagePullSecrets/>
</org.csanchez.jenkins.plugins.kubernetes.PodTemplate>
</templates>
<serverUrl>https://kubernetes.default</serverUrl>
<skipTlsVerify>false</skipTlsVerify>
<namespace>{{ .Release.Namespace }}</namespace>
<jenkinsUrl>http://{{ template "fullname" . }}:8080</jenkinsUrl>
<jenkinsTunnel>{{ template "fullname" . }}:50000</jenkinsTunnel>
<containerCap>10</containerCap>
<retentionTimeout>5</retentionTimeout>
</org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud>
</clouds>
<quietPeriod>5</quietPeriod>
<scmCheckoutRetryCount>0</scmCheckoutRetryCount>
<views>
<hudson.model.AllView>
<owner class="hudson" reference="../../.."/>
<name>All</name>
<filterExecutors>false</filterExecutors>
<filterQueue>false</filterQueue>
<properties class="hudson.model.View$PropertyList"/>
</hudson.model.AllView>
</views>
<primaryView>All</primaryView>
<slaveAgentPort>50000</slaveAgentPort>
<label></label>
<nodeProperties/>
<globalNodeProperties/>
<noUsageStatistics>true</noUsageStatistics>
</hudson>
+15
View File
@@ -0,0 +1,15 @@
{{- if .Values.Persistence.Enabled }}
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: {{ template "fullname" . }}
annotations:
volume.alpha.kubernetes.io/storage-class: {{ .Values.Persistence.StorageClass | quote }}
spec:
accessModes:
- {{ .Values.Persistence.AccessMode | quote }}
resources:
requests:
storage: {{ .Values.Persistence.Size | quote }}
{{- end }}
@@ -0,0 +1,93 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: {{ template "fullname" . }}
labels:
heritage: {{.Release.Service | quote }}
release: {{.Release.Name | quote }}
chart: "{{.Chart.Name}}-{{.Chart.Version}}"
component: "{{.Release.Name}}-{{.Values.Master.Name}}"
annotations:
"helm.sh/created": {{.Release.Time.Seconds | quote }}
spec:
replicas: 1
strategy:
type: RollingUpdate
selector:
matchLabels:
component: "{{.Release.Name}}-{{.Values.Master.Component}}"
template:
metadata:
labels:
heritage: {{.Release.Service | quote }}
release: {{.Release.Name | quote }}
chart: "{{.Chart.Name}}-{{.Chart.Version}}"
component: "{{.Release.Name}}-{{.Values.Master.Component}}"
annotations:
pod.alpha.kubernetes.io/init-containers: '[
{
"name": "copy-default-config",
"image": "{{.Values.Master.Image}}:{{.Values.Master.ImageTag}}",
"command": ["cp", "-n", "/var/jenkins_config/config.xml", "/var/jenkins_home"],
"volumeMounts": [
{
"name": "jenkins-config",
"mountPath": "/var/jenkins_config"
},
{
"name": "jenkins-home",
"mountPath": "/var/jenkins_home"
}
]
}
]'
spec:
securityContext:
runAsUser: 0
containers:
- name: {{ template "fullname" . }}
image: "{{.Values.Master.Image}}:{{.Values.Master.ImageTag}}"
imagePullPolicy: "{{.Values.Master.ImagePullPolicy}}"
args: [ "--argumentsRealm.passwd.$(ADMIN_USER)=$(ADMIN_PASSWORD)", "--argumentsRealm.roles.$(ADMIN_USER)=admin"]
env:
- name: JAVA_OPTS
value: "{{ default "" .Values.Master.JavaOpts}}"
- name: ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: {{ template "fullname" . }}
key: jenkins-admin-password
- name: ADMIN_USER
valueFrom:
secretKeyRef:
name: {{ template "fullname" . }}
key: jenkins-admin-user
ports:
- containerPort: {{.Values.Master.ContainerPort}}
name: http
- containerPort: {{.Values.Master.SlaveListenerPort}}
name: slavelistener
resources:
requests:
cpu: "{{.Values.Master.Cpu}}"
memory: "{{.Values.Master.Memory}}"
volumeMounts:
-
mountPath: /var/jenkins_home
name: jenkins-home
readOnly: false
-
mountPath: /var/jenkins_config
name: jenkins-config
readOnly: true
volumes:
- name: jenkins-config
configMap:
name: {{ template "fullname" . }}
- name: jenkins-home
{{- if .Values.Persistence.Enabled }}
persistentVolumeClaim:
claimName: {{ template "fullname" . }}
{{- else }}
emptyDir: {}
{{- end -}}
@@ -0,0 +1,22 @@
apiVersion: v1
kind: Service
metadata:
name: {{template "fullname" . }}
labels:
heritage: {{.Release.Service | quote }}
release: {{.Release.Name | quote }}
chart: "{{.Chart.Name}}-{{.Chart.Version}}"
component: "{{.Release.Name}}-{{.Values.Master.Component}}"
annotations:
"helm.sh/created": {{.Release.Time.Seconds | quote }}
spec:
ports:
- port: {{.Values.Master.ServicePort}}
name: http
targetPort: {{.Values.Master.ContainerPort}}
- port: {{.Values.Master.SlaveListenerPort}}
targetPort: {{.Values.Master.SlaveListenerPort}}
name: slavelistener
selector:
component: "{{.Release.Name}}-{{.Values.Master.Component}}"
type: {{.Values.Master.ServiceType}}
+17
View File
@@ -0,0 +1,17 @@
apiVersion: v1
kind: Secret
metadata:
name: {{ template "fullname" . }}
labels:
app: {{ template "fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
type: Opaque
data:
{{ if .Values.Master.AdminPassword }}
jenkins-admin-password: {{ .Values.Master.AdminPassword | b64enc | quote }}
{{ else }}
jenkins-admin-password: {{ randAlphaNum 10 | b64enc | quote }}
{{ end }}
jenkins-admin-user: {{ .Values.Master.AdminUser | b64enc | quote }}
+34
View File
@@ -0,0 +1,34 @@
# Default values for jenkins.
# This is a YAML-formatted file.
# Declare name/value pairs to be passed into your templates.
# name: value
Master:
Name: jenkins-master
Image: "gcr.io/kubernetes-charts-ci/jenkins-master-k8s"
ImageTag: "v0.1.0"
ImagePullPolicy: "Always"
Component: "jenkins-master"
AdminUser: admin
# AdminPassword: <defaults to random>
Cpu: "200m"
Memory: "256Mi"
# Set min/max heap here if needed with:
# JavaOpts: "-Xms512m -Xmx512m"
ServicePort: 8080
# For minikube, set this to NodePort, elsewhere use LoadBalancer
ServiceType: LoadBalancer
ContainerPort: 8080
SlaveListenerPort: 50000
Agent:
Image: jenkinsci/jnlp-slave
ImageTag: 2.52
Cpu: "200m"
Memory: "256Mi"
Persistence:
Enabled: true
StorageClass: generic
AccessMode: ReadWriteOnce
Size: 8Gi
+3 -3
View File
@@ -24,15 +24,15 @@ ENV CLOUDSDK_CORE_DISABLE_PROMPTS=1 \
RUN set -x \
&& cd /opt \
&& echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections \
&& apt-get update -y \
&& apt-get update \
&& apt-get install --no-install-recommends -y jq wget python git localepurge ca-certificates \
&& wget -q https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-${GOOGLE_CLOUD_SDK_VERSION}-linux-x86_64.tar.gz \
&& tar xfv google-cloud-sdk-${GOOGLE_CLOUD_SDK_VERSION}-linux-x86_64.tar.gz \
&& tar zxfv google-cloud-sdk-${GOOGLE_CLOUD_SDK_VERSION}-linux-x86_64.tar.gz \
&& ./google-cloud-sdk/install.sh \
&& gcloud components install kubectl \
&& gcloud config set project ${GOOGLE_PROJECT}
RUN cd /opt && wget -q ${HELM_URL} \
&& tar xzfv helm-${HELM_VERSION}-linux-amd64.tar.gz \
&& tar xzfv helm-${HELM_VERSION}-linux-amd64.tar.gz
RUN apt-get -y purge wget localepurge \
&& apt-get clean \
&& cd / \
+1 -1
View File
@@ -18,7 +18,7 @@ set -o nounset
set -o pipefail
# TODO should we inject this. This is creating problems bumping the Docker version
IMAGE_VERSION="test-image:v1.7"
IMAGE_VERSION="test-image:v1.9"
CHART_ROOT=${CHART_ROOT:-$(git rev-parse --show-toplevel)}
IMAGE_NAME=${IMAGE_NAME:-"gcr.io/kubernetes-charts-ci/${IMAGE_VERSION}"}
+1 -1
View File
@@ -12,7 +12,7 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
VERSION=v1.7
VERSION=v1.9
CONTAINER_NAME=test-image
usage() {