1
0

240 Commits

Author SHA1 Message Date
a74507cafb chore(molgenis-jenkins): Add molgenis-it pod template 2018-09-25 13:00:34 +02:00
4c2f9bc035 Merge branch 'feat/helm-in-jenkins' of P129679/molgenis-ops-docker-helm into master 2018-09-24 14:11:44 +02:00
63a08f2264 Merge branch 'doc/helm-role' of P129679/molgenis-ops-docker-helm into master 2018-09-24 13:09:54 +02:00
95d4a1e13e chore(molgenis-jenkins): Add helm container to molgenis pod template. 2018-09-24 11:55:53 +02:00
9dedfc1690 doc: How to configure helm role 2018-09-21 15:17:14 +02:00
16f2701fd2 Merge branch 'add-pvs-to-molgenis' of p281392/molgenis-ops-docker-helm into master 2018-09-12 09:50:34 +02:00
501982ca53 removed redunant volume entry in deployment 2018-09-12 08:19:48 +02:00
7305d54630 updated volume name 2018-09-12 08:17:34 +02:00
c28f08bedd one end to much 2018-09-12 08:15:38 +02:00
321af8f2f2 updated labels and desc 2018-09-12 08:13:33 +02:00
d17c137dd5 added elasticsearch persistence 2018-09-12 08:04:59 +02:00
6f0262d2d9 Merge branch 'chore/remove-secrets' of P129679/molgenis-ops-docker-helm into master 2018-09-11 17:10:10 +02:00
34c8f048b9 also upgraded the default value in values.yaml 2018-09-11 17:08:44 +02:00
d7ccab34c4 version bump and enumerized values for sizing volumes 2018-09-11 17:07:14 +02:00
5fd05f505a updated docs 2018-09-11 16:59:40 +02:00
61d5505126 updated persistence README.md 2018-09-11 16:56:27 +02:00
e5cbcdf933 added retainability for pv's 2018-09-11 15:48:56 +02:00
04bd9cd653 added persistence to questions and bumped chart 2018-09-11 13:51:58 +02:00
88134dbccb Merge branch 'master' of https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm into add-pvs-to-molgenis 2018-09-11 13:46:37 +02:00
8d81b873b7 Merge branch 'add-molgenis-production' of p281392/molgenis-ops-docker-helm into master 2018-09-11 13:41:10 +02:00
dc270c1f65 updated threshold to 25 because instant rebooting 2018-09-11 13:30:43 +02:00
69d3698efb set password required 2018-09-11 13:05:45 +02:00
f1d4a6ee3b specify administrator password 2018-09-11 13:04:28 +02:00
bf770cc05e added thresholds to readiness and liveness probes 2018-09-11 12:57:40 +02:00
6f4f98c091 updated questions 2018-09-11 12:41:56 +02:00
71e59f7639 bumped version to 0.1.0 2018-09-11 12:38:21 +02:00
36f6a242c6 updated memory reservation of MOLGENIS container and updated notation of memory elastic 2018-09-11 12:36:57 +02:00
fc7c564e44 optimized memory limits and removed cpu limit 2018-09-11 12:25:28 +02:00
947e389b92 moved volumes down below in deployment 2018-09-10 22:06:20 +02:00
ed948c40aa referred to right config values.yaml 2018-09-10 22:02:18 +02:00
bfb2e45877 added volumes 2018-09-10 22:00:51 +02:00
59d99deab5 restrcuture deployment 2018-09-10 21:57:39 +02:00
a660aff355 udpated structure 2018-09-10 21:53:29 +02:00
846df81522 udpated structure 2018-09-10 21:49:12 +02:00
a2922c4d49 persistence keys in deploymeny 2018-09-10 21:47:12 +02:00
0c9548069c add subquestion heading 2018-09-10 21:44:34 +02:00
5a98e35273 added persistence properties to values and deployment 2018-09-10 21:41:54 +02:00
9d807d28fc updated start times of liveness probe 2018-09-10 17:38:50 +02:00
d9053b656c updated volume claims 2018-09-10 17:37:50 +02:00
a836ab4e6e chore (molgenis-jenkins): Retrieve pipeline secrets from vault when possible. 2018-09-10 17:28:42 +02:00
581655fe92 Merge branch 'master' of https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm into add-molgenis-production 2018-09-10 17:13:12 +02:00
14b27fc043 updated persistence configuration 2018-09-10 17:05:10 +02:00
cf47b432e2 added persistence to questions 2018-09-10 16:59:14 +02:00
11b25a5df6 added initialDelay 2018-09-10 16:53:58 +02:00
38f89721e7 preview rbac config deleted 2018-09-10 16:46:13 +02:00
008fd5261e Merge branch 'feature/vault' of P129679/molgenis-ops-docker-helm into master 2018-09-10 15:37:12 +02:00
8e39216535 doc (molgenis-vault): Describe ui values in README.md 2018-09-10 15:34:07 +02:00
e0f5d40084 added postgrescluster to chart 2018-09-10 15:23:12 +02:00
4de20d9bd6 add liveness probes 2018-09-10 15:21:10 +02:00
8541b328b8 feat (molgenis-vault): Add vault-ui 2018-09-10 14:15:10 +02:00
5eea95cfbc added elasticsearch 2018-09-10 13:51:09 +02:00
a5be05c7db Merge branch 'feature/vault' of P129679/molgenis-ops-docker-helm into master 2018-09-10 13:03:55 +02:00
12de8ad404 fix (molgenis-vault): default cronjob schedule invalid 2018-09-10 12:07:33 +02:00
b383cc4517 added default value for opencpu cluster 2018-09-10 11:38:51 +02:00
d4307ab3b2 updated version to BETA status 2018-09-10 11:34:51 +02:00
793cf80820 updated README and questions.yml 2018-09-10 11:32:14 +02:00
5b9b653601 doc (molgenis-vault): add icon 2018-09-07 22:45:32 +02:00
1cd6e0f1db doc (molgenis-vault): Clean up documentation 2018-09-07 21:46:55 +02:00
49be7be93e chore (molgenis-vault): Remove unused ingress configuration 2018-09-07 21:46:49 +02:00
ca939363f8 feat (molgenis-vault): Add backup cronjob
Needs to run under service account created by the etcd-operator subchart so there's some template magic needed to figure out what it's called.
2018-09-07 21:46:39 +02:00
7df68882b6 feat (molgenis-vault): Use vault-operator chart and etcd-operator chart to deploy a vault with backup secret. 2018-09-07 21:46:33 +02:00
4683bd6649 chore (molgenis-vault): Add dependencies vault-operator and etcd-operator 2018-09-07 21:46:25 +02:00
9f62298243 chore (molgenis-vault): helm init molgenis-vault 2018-09-07 21:46:04 +02:00
3d93546b47 updated production chart 2018-09-07 16:51:41 +02:00
31567c281a Merge branch 'master' of https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm into add-molgenis-production 2018-09-07 09:50:35 +02:00
89b1639449 added molgenis production chart 2018-09-07 09:50:03 +02:00
599eec5123 Merge branch 'add-dockerhub-to-settings' of p281392/molgenis-ops-docker-helm into master 2018-09-06 15:02:35 +02:00
1b23db334a updated version option to string 2018-09-06 14:59:33 +02:00
433659ad47 removed gogs and added dockerhub to settings 2018-09-06 14:58:21 +02:00
7499c1cc9a Merge branch 'added-selectable-molgenis-versions' of p281392/molgenis-ops-docker-helm into master 2018-09-06 14:51:08 +02:00
9d940a3ebd updated repository reference in deployment 2018-09-06 08:06:25 +02:00
db03e0154b reverted registry to comply to values.yml 2018-09-06 08:04:27 +02:00
9ef26bc177 updated repository to registry 2018-09-06 07:59:43 +02:00
fc8c4cb214 added a group for the version 2018-09-06 07:48:32 +02:00
c30e7b2365 added selectable registry and version 2018-09-06 07:47:22 +02:00
f9089f5ee0 Merge branch 'feature/vault' of P129679/molgenis-ops-docker-helm into master 2018-08-20 12:18:27 +02:00
6e4a3faa46 doc (jenkins) Fix chart README 2018-08-19 23:09:56 +02:00
8f7dfe9ec0 fix (jenkins) Fix skip verify value in vault secret 2018-08-19 23:07:11 +02:00
e088ad8942 fix (jenkins): Move maven's user.home dir to /home/jenkins so that it gets shared between containers in the molgenis pod 2018-08-19 13:46:18 +02:00
2fae637eee feat (jenkins): Create new molgenis pod with vault container and without the secrets.
The new pod has label molgenisv2, the legacy one is still labeled molgenis so existing scripts will keep working.
2018-08-18 23:47:57 +02:00
3a720a8a85 feat (jenkins): Add vault secret 2018-08-18 23:40:57 +02:00
764cda4064 Merge branch 'fix/npm-integration' of p281392/molgenis-ops-docker-helm into master 2018-08-18 21:34:23 +02:00
b36759fab2 updated docs and fixed npm integration 2018-08-06 21:44:00 +02:00
83e9a428d7 Merge branch 'add-npm-token' of p281392/molgenis-ops-docker-helm into master 2018-08-06 20:41:57 +02:00
1215e3edbe added alpine container 2018-08-06 20:40:51 +02:00
f19b014446 Merge branch 'master' of https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm into add-npm-token 2018-08-06 20:39:13 +02:00
9443f9a0bb Merge branch 'add-ops-jobs' of p281392/molgenis-ops-docker-helm into master 2018-08-06 20:38:44 +02:00
c43bf50180 Merge branch 'master' of p281392/molgenis-ops-docker-helm into master 2018-08-06 20:36:48 +02:00
d76aced730 update version 2018-08-06 20:31:10 +02:00
4fe58b496b Merge branch 'feature/add-gogs-settings' of p281392/molgenis-ops-docker-helm into master 2018-08-06 17:13:19 +02:00
7a54c88da1 Merge branch 'feat/add-saucelabs' of p281392/molgenis-ops-docker-helm into master 2018-08-06 16:55:51 +02:00
01b8893d5b updated saucelabs user 2018-08-02 22:31:57 +02:00
9c6865336f added saucelabs cred 2018-08-02 07:49:15 +02:00
59e42a3048 updated node container and removed alpine containers 2018-08-01 22:36:02 +02:00
87951be9c4 added ops jobs for building releases 2018-08-01 22:27:41 +02:00
b5128bc253 Merge branch 'add-icons' of p281392/molgenis-ops-docker-helm into master 2018-07-30 22:17:28 +02:00
592e93b40d fixed uppercase 2018-07-30 22:15:37 +02:00
a8a895248b updated icons for httpd and molgenis preview 2018-07-30 22:13:26 +02:00
65023d9f2d Merge branch 'updated-questions' of p281392/molgenis-ops-docker-helm into master 2018-07-30 21:29:28 +02:00
521c92f379 added group 2018-07-30 21:28:51 +02:00
91e38eab6b merge with blessed 2018-07-30 21:27:46 +02:00
936e1252fd added Java runtime question 2018-07-30 21:23:13 +02:00
ec42841aac Merge branch 'master' of p281392/molgenis-ops-docker-helm into master 2018-07-30 21:09:34 +02:00
c269997fd0 added MOLGENIS resources to questions 2018-07-30 21:08:40 +02:00
a0e11833d2 updated structure 2018-07-30 21:06:03 +02:00
557bcf5354 updated options 2018-07-30 21:05:16 +02:00
f35e8c62c1 updated helm cahrt 2018-07-30 20:56:28 +02:00
c10544c47e updated questions 2018-07-30 17:52:07 +02:00
e725951f04 Merge branch 'add-questions' of p281392/molgenis-ops-docker-helm into master 2018-07-30 17:32:40 +02:00
adfd742ecb add questions and updated post body 2018-07-30 17:23:58 +02:00
4b2a3a01d9 Merge branch 'fix/max-upload-size' of p281392/molgenis-ops-docker-helm into master 2018-07-30 15:35:19 +02:00
7ff04e01d3 updated proxy body size to nginx 2018-07-30 15:34:10 +02:00
05708f3885 Merge branch 'fix/max-upload-size' of p281392/molgenis-ops-docker-helm into master 2018-07-30 15:10:47 +02:00
114b0acbfa set max size to zero 2018-07-30 15:10:07 +02:00
91af7787b0 fix upload large files 2018-07-30 15:08:11 +02:00
6a77c1e688 added sonar token 2018-07-25 08:45:37 +02:00
63a99c2c00 add gogs settings 2018-07-23 22:21:11 +02:00
37de4f870f Merge branch 'master' of p281392/molgenis-ops-docker-helm into master 2018-07-20 00:29:09 +02:00
44f0962857 version bump to 0.6.5 2018-07-20 00:27:13 +02:00
5f04d3d505 Merge branch 'master' of p281392/molgenis-ops-docker-helm into master 2018-07-20 00:20:07 +02:00
dcf6d3d137 make default view configurable 2018-07-20 00:14:25 +02:00
0afd014bf6 Merge branch 'master' of p281392/molgenis-ops-docker-helm into master 2018-07-20 00:05:41 +02:00
e6523827e3 added keys to jobs 2018-07-20 00:04:46 +02:00
e436bd27b1 Merge branch 'master' of p281392/molgenis-ops-docker-helm into master 2018-07-19 23:53:17 +02:00
4ebdf6e66a fix(views): missed curly braces 2018-07-19 23:51:58 +02:00
60be819212 Merge branch 'master' of p281392/molgenis-ops-docker-helm into master 2018-07-19 23:44:33 +02:00
4482ebef4b forgot dollar sign 2018-07-19 23:42:39 +02:00
0a85053e15 fix(views): added key and index to loop through array 2018-07-19 23:40:57 +02:00
4d357aa1d5 Merge branch 'master' of p281392/molgenis-ops-docker-helm into master 2018-07-19 23:30:16 +02:00
b31082c4f4 fix(views): get other key from values to create views 2018-07-19 23:27:38 +02:00
bc83a4f224 Merge branch 'master' of p281392/molgenis-ops-docker-helm into master 2018-07-19 23:20:59 +02:00
7a262b88c0 bumped version to 0.6.0 (configurable views) 2018-07-19 23:20:10 +02:00
614b578ecd Merge branch 'make-views-configurable' of p281392/molgenis-ops-docker-helm into master 2018-07-19 23:18:26 +02:00
586e777f77 Merge branch 'master' of https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm into make-views-configurable 2018-07-19 23:17:33 +02:00
ef59e83d5c Merge branch 'master' of p281392/molgenis-ops-docker-helm into master 2018-07-19 23:17:01 +02:00
3499710765 make views confiogurable 2018-07-19 23:15:28 +02:00
7bcfb04822 Merge branch 'master' of P129679/molgenis-ops-docker-helm into master 2018-07-19 22:53:34 +02:00
c673afe5cd feature (jenkins): Split off node pod 2018-07-19 22:51:27 +02:00
4667af0968 updated version to 0.3.0 2018-07-19 22:51:02 +02:00
0cf23a8d47 Merge branch 'master' of p281392/molgenis-ops-docker-helm into master 2018-07-19 22:46:21 +02:00
2430354e98 bumped version to 0.5.0 2018-07-19 22:40:51 +02:00
4ad7d69169 Merge branch 'master' of P129679/molgenis-ops-docker-helm into master 2018-07-19 22:40:00 +02:00
85a46c5196 Merge branch 'version-bump-to-04.0' of p281392/molgenis-ops-docker-helm into master 2018-07-19 22:36:54 +02:00
2a0a9015df fix(jenkins): Make container working dir configurable 2018-07-19 22:35:53 +02:00
bc33f83b07 updated version to 0.4.0 2018-07-19 22:25:15 +02:00
bd004fd074 Merge branch 'add-node-container' of p281392/molgenis-ops-docker-helm into master 2018-07-19 22:08:09 +02:00
b20fcb5f7e Merge branch 'added-gogs' of p281392/molgenis-ops-docker-helm into master 2018-07-19 22:06:39 +02:00
0207ffdfa2 Add node container to Jenkins config 2018-07-19 21:48:38 +02:00
ed25e21817 added gogs webhook plugin 2018-07-19 21:24:53 +02:00
e3b2b08886 Merge branch 'added-views' of p281392/molgenis-ops-docker-helm into master 2018-07-19 20:31:40 +02:00
b2ffdb6835 renamed job for httpd docker 2018-07-19 19:18:38 +02:00
cdef5836d5 added views 2018-07-19 19:16:21 +02:00
249b15b777 Merge branch 'fix/scm-and-cred' of p281392/molgenis-ops-docker-helm into master 2018-07-19 18:54:45 +02:00
8a4b4c28aa bumped version of app and chart 2018-07-19 18:53:51 +02:00
9103f8ba30 fix issues with scm urls and credentials 2018-07-19 12:37:11 +02:00
e7d364d2de Merge branch 'master' of P129679/molgenis-ops-docker-helm into master 2018-07-16 13:41:30 +02:00
e72703003f chore (molgenis-jenkins) update version 0.3.0 -> 0.3.1 2018-07-16 12:58:06 +02:00
5596956b98 doc (molgenis-jenkins): update rancher port number 7443 -> 7777 2018-07-16 12:58:06 +02:00
90de173cc4 fix (molgenis-jenkins): Github -> GitHub 2018-07-16 12:58:06 +02:00
2306bcb908 feature (molgenis-jenkins): Add molgenis-it pod template 2018-07-16 12:57:59 +02:00
f7b4d0d581 Merge branch 'feature/molgenis-preview' of p281392/molgenis-ops-docker-helm into master 2018-07-15 12:37:58 +02:00
47056dea3a add MOLGENIS preview 2018-07-14 13:13:23 +02:00
24220fd982 Merge branch 'add-github-delegation' of p281392/molgenis-ops-docker-helm into master 2018-07-04 12:41:08 +02:00
e42be9dd2e Merge branch 'master' of p281392/molgenis-ops-docker-helm into master 2018-07-04 12:27:58 +02:00
d8324a937c update keys in config.tpl according to values.yml 2018-07-04 00:04:13 +02:00
79832a74cb updated docker description 2018-07-03 23:58:50 +02:00
606716abfa merge with master 2018-07-03 23:48:28 +02:00
10557d2d8f feature(github): delegation to github for user management 2018-07-03 23:44:36 +02:00
79b862d548 Merge branch 'add-docker-hub-cred' of p281392/molgenis-ops-docker-helm into master 2018-07-02 22:27:26 +02:00
238da8b22b changed name because of weird policy dockerhub 2018-07-02 20:23:09 +02:00
800d7a934c add docker hub credentials 2018-07-02 20:13:01 +02:00
b291f5450e add nexus password environment 2018-07-02 14:10:58 +02:00
e172d52f1a Merge branch 'master' of P129679/molgenis-ops-docker-helm into master 2018-07-02 12:41:42 +02:00
eae999a575 Request resources for the maven container to prevent overly many concurrent builds. 2018-07-02 12:34:37 +02:00
714302fde9 Merge branch 'master' of P129679/molgenis-ops-docker-helm into master 2018-07-02 11:53:48 +02:00
b58575be5d Forget about the integration test containers for now. 2018-07-02 11:49:08 +02:00
4fd527d024 Merge branch 'add-nexus-secret' of p281392/molgenis-ops-docker-helm into master 2018-07-02 08:40:10 +02:00
4a3b7784c5 Merge branch 'master' of https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm into add-nexus-secret 2018-07-01 22:13:47 +02:00
fcee8f3368 Merge branch 'master' of P129679/molgenis-ops-docker-helm into master 2018-07-01 20:47:57 +02:00
9711660fc4 containerPort alone is enough, hostPort makes it exposed on the host node 2018-07-01 00:32:47 +02:00
4cfb7d9d26 Fix nexus yarn/npm config. 2018-06-30 21:26:19 +02:00
00a2032aea Add operations jobs 2018-06-30 17:14:20 +02:00
a5695a02d6 Merge branch 'master' of P129679/molgenis-ops-docker-helm into master 2018-06-30 00:22:31 +02:00
de4b3f126b Merge branch 'add-gogs-secrete' of p281392/molgenis-ops-docker-helm into master 2018-06-29 23:54:58 +02:00
547c3e2090 updated naming 2018-06-29 23:48:31 +02:00
52c64e6d29 Fine tune the jenkins config 2018-06-29 23:44:50 +02:00
633863e7f7 Fix cat and tty 2018-06-29 23:37:47 +02:00
62114aecc4 Increase container cap 2018-06-29 23:31:08 +02:00
28efad8cb8 add gogs secrets 2018-06-29 23:30:38 +02:00
22a53eca6d added jenkins secret 2018-06-29 23:02:57 +02:00
805b248a19 Merge branch 'master' of https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm 2018-06-29 22:50:01 +02:00
840eedc5b9 update nexus docs 2018-06-29 22:21:45 +02:00
851bc64e50 Merge branch 'master' of p281392/molgenis-ops-docker-helm into master 2018-06-29 22:12:02 +02:00
8919984691 Merge branch 'master' of https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm 2018-06-29 21:57:46 +02:00
eea9db7664 reset httpdservice won't work without it 2018-06-29 21:57:28 +02:00
47f5e8d1f1 Merge branch 'master' of P129679/molgenis-ops-docker-helm into master 2018-06-29 21:42:57 +02:00
e91ea8d22f Update values.yaml 2018-06-29 19:35:11 +02:00
f32c2e0d52 Add postgres image 2018-06-29 15:24:51 +02:00
687a1817f9 rename pod and don't namespace the label 2018-06-29 15:21:00 +02:00
28ef3d0252 Merge branch 'master' of https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm 2018-06-29 15:10:19 +02:00
9208f4daaa enable TTY 2018-06-29 15:09:28 +02:00
21bd807b3d Merge branch 'master' of P129679/molgenis-ops-docker-helm into master 2018-06-29 14:56:07 +02:00
b959ae3f99 Make ports configurable in values 2018-06-29 14:54:13 +02:00
02e397b253 Now I understand what . is, I can ditch all the variable references. 2018-06-29 14:10:14 +02:00
f1616c7ed8 Merge branch 'master' of https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm 2018-06-29 14:04:25 +02:00
d1a1a2a4c6 Revert "see if removing the other templates makes the jenkins one come up again."
This reverts commit 2876973a6a.
2018-06-29 14:04:08 +02:00
a83eb0ff4f fixed icon for nexus 2018-06-29 14:03:50 +02:00
b8cceee753 Rename GithubToken => GitHubToken 2018-06-29 12:58:45 +02:00
1d1035c51d Fix #8: Make the containers in the jenkins pod template configurable through values 2018-06-29 12:52:25 +02:00
3eec43fad5 Update README. 2018-06-29 09:53:48 +02:00
523f9194fc restructure dirs 2018-06-29 08:56:49 +02:00
22a8bdb41f Merge branch 'fix-httpd-chart' of p281392/molgenis-ops-docker-helm into master 2018-06-29 08:53:12 +02:00
73a42d9fe0 fixed title 2018-06-29 08:52:21 +02:00
473a900bc1 Merge branch 'fix-httpd-chart' of p281392/molgenis-ops-docker-helm into master 2018-06-29 08:48:53 +02:00
594d3781ab fixed chart.yml 2018-06-29 08:47:38 +02:00
b0a0029c1a Merge branch 'master' of p281392/molgenis-ops-docker-helm into master 2018-06-29 07:31:04 +02:00
c91600b4e5 move README nexus 2018-06-29 07:29:37 +02:00
2876973a6a see if removing the other templates makes the jenkins one come up again. 2018-06-29 00:26:45 +02:00
f6ba15e9f5 Switch to github-branch-source plugin. 2018-06-29 00:15:41 +02:00
3ac611e69f Fix codecov step
* Add alpine container with curl to run codecov in
* Add JENKINS_URL env var so codecov recognizes that this is jenkins ci.
2018-06-29 00:15:16 +02:00
20e72c9f5c Merge branch 'master' of P129679/molgenis-ops-docker-helm into master 2018-06-28 15:25:12 +02:00
012b58ea67 Update settings.xml value. 2018-06-28 13:09:13 +02:00
19b2ff1113 Fix settings.xml filename. 2018-06-28 12:54:23 +02:00
3f812f7f74 Fix mount point. 2018-06-28 12:17:23 +02:00
b8d061487e fix(httpd): chart.yml was brokebn 2018-06-28 12:15:41 +02:00
25b592e6fe Merge branch 'updated-httpd-chart' of p281392/molgenis-ops-docker-helm into master 2018-06-28 12:13:12 +02:00
06d1880dc4 Give proper name to file secret 2018-06-28 12:10:07 +02:00
107d503976 Fix keys in values file 2018-06-28 12:05:49 +02:00
f1ee53ccb4 Merge branch 'master' of https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm 2018-06-28 11:52:04 +02:00
9e55b6be64 Merge branch 'master' of p281392/molgenis-ops-docker-helm into master 2018-06-28 11:07:02 +02:00
628825475a updated documentation 2018-06-27 22:12:27 +02:00
ac1669efd2 updated httpd chart 2018-06-27 22:06:41 +02:00
120a4afba4 fix: updated readme 2018-06-27 21:20:13 +02:00
bd68f93383 updated name 2018-06-27 18:15:06 +02:00
80c2085bfe bumped version 2018-06-27 18:10:11 +02:00
eecbf67ff2 bumped version 2018-06-27 18:08:12 +02:00
b30a4e6e21 bumped version 2018-06-27 18:06:39 +02:00
e33e6cf627 bumped version 2018-06-27 18:03:05 +02:00
ccc3be8a9d volumes: make volumes abstract 2018-06-27 18:02:30 +02:00
09c762c1b3 volumes permissions 2018-06-27 17:18:25 +02:00
86 changed files with 6392 additions and 620 deletions

129
README.md
View File

@ -1,39 +1,140 @@
# MOLGENIS Helm templates
These are the Helm templates that we will use for MOLGENIS operations. There are some prerequisites you need.
These are the Helm templates that we will use for MOLGENIS operations. Basic concepts in respect to docker you need to know.
**Deployments**
Are a set of pods that will be deployed according to configuration that is usually managed bij Helm. These pods interact with eachother by being in the same namespace created by kubernetes according to the deployment configuration.
**Pods**
A pod is wrapper around a container. It will recreate the container when it is shutdown for some reason and interact with other pods when needed.
**Containers**
A container is a docker-container that is created from a docker image. It could be seen as an VM for example
**Images**
An image is a template for a container some sort of boot script but also contains the os for example. A build dockerfile, if you will.
**Prerequisites**
There are some prerequisites you need.
- docker
- minikube
## Useful commands for Kubernetes
## Kubernetes
When you want to use kubernetes there are some commands you need to know. Also running on a remote cluster will be a must have to control your whole DTAP.
### Useful commands
Commands that can be used to get information from a kubernetes cluster
- kubectl get pods
**Pods**
- ```kubectl get pods (optional: [--all-namspaces])```
Gets alls running instances of containers from a certain deployment
- kubectl get services
- ```kubectl describe pod #pod name# --namespace=#namesspace#```
Describes the pod initialization, also displays error messages more accurately if they occur
- ```kubectl remove pod #pod name# --namespace=#namespace# (optional: [--force] [--grace-period=0])```
Removes a pod from the system (but will restart if the option is set in the deployment,yaml *[see note]*).
**note:** You can not do this while the deployment of the service is still there
**Services**
- ```kubectl get services```
Gets all services from a deployment
- kubectl get pv
**Volumes**
- ```kubectl get pv```
Gets all persistant volumes
- kubectl get pvc
- ```kubectl get pvc```
Gets all persistent volume claims
- kubectl get deployments
**Deployments**
- ```kubectl get deployments```
Gets all deployments (comparable with docker-compose)
## Remote clusters
When you want to see what is running on the clusters at the CIT you have to make a context switch.
You can access the cluster with kubeconfig-files. You can obtain these by downloading them from the
MOLGENIS kubernetes cluster.
- Goto https://rancher.molgenis.org:7443
- Goto
- Go to https://rancher.molgenis.org:7777 and login
- Go to Rancher --> Cluster: *#name#* --> *Kubeconfig File*
- Go to a **Terminal** where ```kubectl``` is available
- Add this configuration to ~/.kube/config (or place a new file besides this one)
*Example*:
```bash
# When you added the MOLGENIS configuration to the original configuration
kubectl config use-context molgenis
# or when you placed the MOLGENIS configuration besides the original one
kubectl config use-context molgenis --kubeconfig=*full path to molgenis config*
```
- You can now access all facilities of the MOLGENIS cluster like it is running locally
*Example:*
```bash
kubectl get pods --namespace=*#namespace of application#*
```
## Useful commands for Helm
## Helm
- helm install .
This repository is serves also as a catalogue for Rancher. We have serveral apps that are served through this repoistory. e.g.
- [Jenkins](molgenis-jenkins/README.md)
- [NEXUS](molgenis-nexus/README.md)
- [HTTPD](molgenis-httpd/README.md)
- [MOLGENIS preview](molgenis-preview/README.md)
- [MOLGENIS vault](molgenis-vault/README.md)
### Useful commands
You can you need to know to easily develop and deploy helm-charts
- ```helm lint .```
To test your helm chart for code errors.
- ```helm install . --dry-run --debug```
Check if your configuration deploys on a kubernetes cluster and check the configuration
- ```helm install . #release name# --namespace #remote namespace#```
Do it in the root of the project where the Chart.yaml is located
It installs a release of a kubernetes stack. You also store this as an artifact in a kubernetes repository
- helm list
- ```helm list```
Lists all installed releases
- helm delete #release#
Performs a sort of mvn clean on your workspace. Very handy for zombie persistent volumes or claims.
- ```helm delete #release#```
Performs a sort of mvn clean on your workspace. Very handy for zombie persistent volumes or claims.
- ```install tiller on remote cluster```
To install tiller on a remote cluster you need an rbac-config.yml.
```kubectl create -f rbac-config.yaml```
When you have defined the yaml you can add the tiller to the cluster by following the steps below.
```helm init --service-account tiller```

View File

@ -1,5 +0,0 @@
apiVersion: v1
appVersion: "1.0"
description: A Helm chart for Kubernetes
name: httpd
version: 0.1.2

View File

@ -1,64 +0,0 @@
categories:
- MOLGENIS
questions:
- variable: molgenisUsername
default: "molgenis"
description: "User of the application"
type: string
required: true
label: MOLGENIS username
group: "MOLGENIS Settings"
- variable: molgenisEmail
default: "admin@molgenis.org"
description: "Admin email"
type: string
required: true
label: MOLGENIS admin email
group: "MOLGENIS Settings"
- variable: persistence.enabled
default: "false"
description: "Enable persistent volume for MOLGENIS"
type: boolean
required: true
label: MOLGENIS Persistent Volume Enabled
show_subquestion_if: true
group: "MOLGENIS Settings"
subquestions:
- variable: persistence.size
default: "10Gi"
description: "Persistent Volume Size"
type: string
label: MOLGENIS Volume Size
- variable: persistence.storageClass
default: ""
description: "If undefined or null, uses the default StorageClass. Default to null"
type: storageclass
label: Default StorageClass for MOLGENIS
- variable: ingress.hosts[0].name
default: "test.molgenis.org"
description: "Hostname for your stack"
type: hostname
required: true
group: "Services and Load Balancing"
label: Hostname
- variable: httpd.hostname
default: "test.molgenis.org"
description: "Hostname for your services (comma separated, example: [hostname]:[port])"
type: string
required: false
group: "Apache configuration"
label: Hostname
- variable: httpd.proxy
default: ""
description: "Proxy for your services (comma separated, example: [service]:[port]:[path])"
type: string
required: false
group: "Apache configuration"
label: Proxy
- variable: httpd.redirect
default: ""
description: "Redirection urls for your services (comma separated, example: [redirection_url])"
type: string
required: false
group: "Apache configuration"
label: Redirection

View File

@ -0,0 +1,8 @@
apiVersion: v1
appVersion: "1.0"
description: HTTPD for MOLGENIS
name: molgenis-httpd
version: 0.1.0
sources:
- https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm.git
icon: https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm/raw/master/molgenis-httpd/catalogIcon-molgenis-httpd.svg

15
molgenis-httpd/README.md Normal file
View File

@ -0,0 +1,15 @@
# MOLGENIS - HTTPD Helm Chart
HTTPD (web)server for kubernetes to deploy on a kubernetes cluster with NFS-share
## Chart Details
This chart will deploy:
- 1 HTTPD container
## Installing the Chart
etc.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 89 KiB

View File

@ -0,0 +1,31 @@
categories:
- MOLGENIS
questions:
- variable: ingress.hosts[0].name
default: "test.molgenis.org"
description: "Hostname for your stack"
type: hostname
required: true
group: "Services and Load Balancing"
label: Hostname
- variable: httpd.hostname
default: "test.molgenis.org"
description: "Hostname for your services (comma separated, example: [hostname]:[port])"
type: string
required: false
group: "Apache configuration"
label: Hostname
- variable: httpd.proxy
default: ""
description: "Proxy for your services (comma separated, example: [service]:[port]:[path])"
type: string
required: false
group: "Apache configuration"
label: Proxy
- variable: httpd.redirect
default: ""
description: "Redirection urls for your services (comma separated, example: [redirection_url])"
type: string
required: false
group: "Apache configuration"
label: Redirection

View File

@ -24,9 +24,8 @@ spec:
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 80
protocol: TCP
- name: {{ .Values.service.name }}
containerPort: {{ .Values.service.port }}
env:
- name: SERVER_NAME
value: "{{ .Values.httpd.hostname }}"

View File

@ -10,10 +10,9 @@ metadata:
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
- name: {{ .Values.service.name }}
port: {{ .Values.service.port }}
selector:
app: {{ template "httpd.name" . }}
release: {{ .Release.Name }}

View File

@ -10,6 +10,7 @@ image:
pullPolicy: Always
service:
name: httpd
type: ClusterIP
port: 80
@ -17,12 +18,9 @@ httpd:
proxy: httpd:80:/
redirect: redirect.molgenis.local
hostname: test.molgenis.local
volume:
username: molgenis
email: admin@molgenis.org
ingress:
enabled: false
enabled: true
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"

View File

@ -1,7 +1,7 @@
name: molgenis-jenkins
home: https://jenkins.io/
version: 0.2.1
appVersion: 2.107
version: 0.7.0
appVersion: 2.121
description: Molgenis installation for the jenkins chart.
sources:
- https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm.git

View File

@ -1,10 +1,7 @@
# Molgenis 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 <mailto:carlos@apache.org>
Jenkins master and slave cluster utilizing the Jenkins Kubernetes plugin.
Wraps [the kuberenetes jenkins chart](https://github.com/kubernetes/charts/tree/master/stable/jenkins), see documentation there!
## Chart Details
@ -15,223 +12,100 @@ This chart will do the following:
## Installing the Chart
In the rancher UI, choose the molgenis-jenkins app from the catalog and deploy it.
Usually, you'll be deploying this to the molgenis cluster.
In the [Rancher Catalog](https://rancher.molgenis.org:7443/g/catalog), add the latest version of this repository.
In the [molgenis cluster management page](https://rancher.molgenis.org:7443/p/c-mhkqb:project-2pf45/apps), choose the
catalog, pick the molgenis-jenkins app from the catalog and deploy it.
## Configuration
The following tables list the configurable parameters of the Jenkins chart and their default values.
You can paste these values into the Rancher Answers if you like.
Array values can be added as {value, value, value}, e.g.
When deploying, you can paste values into the Rancher Answers to override the defaults in this chart.
Array values can be added as {value, value, value}.
```
jenkins.Master.InstallPlugins={kubernetes:1.8.4, workflow-aggregator:2.5, workflow-job:2.21, credentials-binding:1.16, git:3.9.1}
jenkins.Master.HostName=jenkins.molgenis.org
jenkins.Master.AdminPassword=pa$$word
jenkins.Persistence.Enabled=false
jenkins.Master.InstallPlugins={kubernetes:1.8.4, workflow-aggregator:2.5, workflow-job:2.21, credentials-binding:1.16, git:3.9.1, blueocean:1.6.2, github-oauth:0.29}
jenkins.Master.Security.UseGitHub=false
## if UseGitHub=true
jenkins.Master.Security.GitHub.ClientID=id
jenkins.Master.Security.GitHub.ClientSecret=S3cr3t
## end UseGitHub=true
PipelineSecrets.Env.PGPPassphrase=literal:S3cr3t
```
> Because we use jenkins as a sub-chart, you should prefix all values with `jenkins`!
### Jenkins Master
| Parameter | Description | Default |
| --------------------------------- | ------------------------------------ | ---------------------------------------------------------------------------- |
| `nameOverride` | Override the resource name prefix | `jenkins` |
| `fullnameOverride` | Override the full resource names | `jenkins-{release-name}` (or `jenkins` if release-name is `jenkins`) |
| `Master.Name` | Jenkins master name | `jenkins-master` |
| `Master.Image` | Master image name | `jenkinsci/jenkins` |
| `Master.ImageTag` | Master image tag | `lts` |
| `Master.ImagePullPolicy` | Master image pull policy | `Always` |
| `Master.ImagePullSecret` | Master image pull secret | Not set |
| `Master.Component` | k8s selector key | `jenkins-master` |
| `Master.UseSecurity` | Use basic security | `true` |
| `Master.AdminUser` | Admin username (and password) created as a secret if useSecurity is true | `admin` |
| `Master.Cpu` | Master requested cpu | `200m` |
| `Master.Memory` | Master requested memory | `256Mi` |
| `Master.InitContainerEnv` | Environment variables for Init Container | Not set |
| `Master.ContainerEnv` | Environment variables for Jenkins Container | Not set |
| `Master.RunAsUser` | uid that jenkins runs with | `0` |
| `Master.FsGroup` | uid that will be used for persistent volume | `0` |
| `Master.ServiceAnnotations` | Service annotations | `{}` |
| `Master.ServiceType` | k8s service type | `LoadBalancer` |
| `Master.ServicePort` | k8s service port | `8080` |
| `Master.NodePort` | k8s node port | Not set |
| `Master.HealthProbes` | Enable k8s liveness and readiness probes | `true` |
| `Master.HealthProbesLivenessTimeout` | Set the timeout for the liveness probe | `120` |
| `Master.HealthProbesReadinessTimeout` | Set the timeout for the readiness probe | `60` |
| `Master.HealthProbeLivenessFailureThreshold` | Set the failure threshold for the liveness probe | `12` |
| `Master.ContainerPort` | Master listening port | `8080` |
| `Master.SlaveListenerPort` | Listening port for agents | `50000` |
| `Master.DisabledAgentProtocols` | Disabled agent protocols | `JNLP-connect JNLP2-connect` |
| `Master.CSRF.DefaultCrumbIssuer.Enabled` | Enable the default CSRF Crumb issuer | `true` |
| `Master.CSRF.DefaultCrumbIssuer.ProxyCompatability` | Enable proxy compatibility | `true` |
| `Master.CLI` | Enable CLI over remoting | `false` |
| `Master.LoadBalancerSourceRanges` | Allowed inbound IP addresses | `0.0.0.0/0` |
| `Master.LoadBalancerIP` | Optional fixed external IP | Not set |
| `Master.JMXPort` | Open a port, for JMX stats | Not set |
| `Master.CustomConfigMap` | Use a custom ConfigMap | `false` |
| `Master.Ingress.Annotations` | Ingress annotations | `{}` |
| `Master.Ingress.TLS` | Ingress TLS configuration | `[]` |
| `Master.InitScripts` | List of Jenkins init scripts | Not set |
| `Master.CredentialsXmlSecret` | Kubernetes secret that contains a 'credentials.xml' file | Not set |
| `Master.SecretsFilesSecret` | Kubernetes secret that contains 'secrets' files | Not set |
| `Master.Jobs` | Jenkins XML job configs | Not set |
| `Master.InstallPlugins` | List of Jenkins plugins to install | `kubernetes:0.11 workflow-aggregator:2.5 credentials-binding:1.11 git:3.2.0` |
| `Master.ScriptApproval` | List of groovy functions to approve | Not set |
| `Master.NodeSelector` | Node labels for pod assignment | `{}` |
| `Master.Affinity` | Affinity settings | `{}` |
| `Master.Tolerations` | Toleration labels for pod assignment | `{}` |
| `NetworkPolicy.Enabled` | Enable creation of NetworkPolicy resources. | `false` |
| `NetworkPolicy.ApiVersion` | NetworkPolicy ApiVersion | `extensions/v1beta1` |
| `rbac.install` | Create service account and ClusterRoleBinding for Kubernetes plugin | `false` |
| `rbac.apiVersion` | RBAC API version | `v1beta1` |
| `rbac.roleRef` | Cluster role name to bind to | `cluster-admin` |
You can use [all configuration values of the jenkins subchart](https://github.com/kubernetes/charts/tree/master/stable/jenkins).
> Because we use jenkins as a sub-chart, you should prefix all value keys with `jenkins`!
### Jenkins Agent
### GitHub Authentication delegation
You need to setup a MOLGENIS - Jenkins GitHub OAuth App. You can do this by accessing this url: [add new OAuth app](https://github.com/settings/applications/new).
| Parameter | Description | Default |
| ----------------------- | ----------------------------------------------- | ---------------------- |
| `Agent.AlwaysPullImage` | Always pull agent container image before build | `false` |
| `Agent.Enabled` | Enable Kubernetes plugin jnlp-agent podTemplate | `true` |
| `Agent.Image` | Agent image name | `jenkinsci/jnlp-slave` |
| `Agent.ImagePullSecret` | Agent image pull secret | Not set |
| `Agent.ImageTag` | Agent image tag | `2.62` |
| `Agent.Privileged` | Agent privileged container | `false` |
| `Agent.Cpu` | Agent requested cpu | `200m` |
| `Agent.Memory` | Agent requested memory | `256Mi` |
| `Agent.volumes` | Additional volumes | `nil` |
### Secrets
When deployed, the chart creates a couple of kubernetes secrets that get used by jenkins.
You can override the values at deploy time but otherwise also configure them
[in Rancher](https://rancher.molgenis.org:7443/p/c-mhkqb:project-2pf45/secrets) or through kubectl.
#### Vault
The vault secret gets mounted in the vault pod so pipeline scripts can retrieve secrets from the vault.
| Parameter | Description | Default |
| ------------------------- | ------------------------------------------ | ---------------------------------------------- |
| `secret.vault.token` | Token to log into the hashicorp vault | `xxxx` |
| `secret.vault.addr` | Address of the vault | `https:vault-operator.vault-operator.svc:8200` |
| `secret.vault.skipVerify` | Skip verification of the https connection | `1` |
#### GitHub
Token used by Jenkins to authenticate on GitHub.
| Parameter | Description | Default |
| --------------------- | ------------------------ | ------------------ |
| `secret.gitHub.user` | username for the account | `molgenis-jenkins` |
| `secret.gitHub.token` | token for the account | `xxxx` |
#### Gogs
Token used by Jenkins to authenticate on the [RuG Webhosting Gogs](https://git.webhosting.rug.nl).
| Parameter | Description | Default |
| ------------------- | ------------------------ | --------- |
| `secret.gogs.user` | username for the account | `p281392` |
| `secret.gogs.token` | token for the account | `xxxx` |
#### Legacy:
##### Docker Hub
Account used in pipeline builds to push docker images to `hub.docker.com`.
> They should read `secret/gcc/account/dockerhub` from vault instead!
| Parameter | Description | Default |
| --------------------------- | ------------------------ | --------------- |
| `secret.dockerHub.user` | username for the account | `molgenisci` |
| `secret.dockerHub.password` | password for the account | `xxxx` |
##### Registry
Account used in pipeline builds to push docker images to `registry.molgenis.org`.
> They should read `secret/ops/account/nexus` from vault instead!
| Parameter | Description | Default |
| --------------------------- | ------------------------ | --------- |
| `secret.dockerHub.user` | username for the account | `admin` |
| `secret.dockerHub.password` | password for the account | `xxxx` |
## Command line use
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,
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 stable/jenkins
$ helm install --name jenkins -f values.yaml molgenis-jenkins
```
> **Tip**: You can use the default [values.yaml](values.yaml)
## Mounting volumes into your Agent pods
Your Jenkins Agents will run as pods, and it's possible to inject volumes where needed:
```yaml
Agent:
volumes:
- type: Secret
secretName: jenkins-mysecrets
mountPath: /var/run/secrets/jenkins-mysecrets
```
The supported volume types are: `ConfigMap`, `EmptyDir`, `HostPath`, `Nfs`, `Pod`, `Secret`. Each type supports a different set of configurable attributes, defined by [the corresponding Java class](https://github.com/jenkinsci/kubernetes-plugin/tree/master/src/main/java/org/csanchez/jenkins/plugins/kubernetes/volumes).
## NetworkPolicy
To make use of the NetworkPolicy resources created by default,
install [a networking plugin that implements the Kubernetes
NetworkPolicy spec](https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy#before-you-begin).
For Kubernetes v1.5 & v1.6, you must also turn on NetworkPolicy by setting
the DefaultDeny namespace annotation. Note: this will enforce policy for _all_ pods in the namespace:
kubectl annotate namespace default "net.beta.kubernetes.io/network-policy={\"ingress\":{\"isolation\":\"DefaultDeny\"}}"
Install helm chart with network policy enabled:
$ helm install stable/jenkins --set NetworkPolicy.Enabled=true
## Persistence
The Jenkins image stores persistence under `/var/jenkins_home` path of the container. A dynamically managed Persistent Volume
Claim is used to keep the data across deployments, by default. This is known to work in GCE, AWS, and minikube. Alternatively,
a previously configured Persistent Volume Claim can be used.
It is possible to mount several volumes using `Persistence.volumes` and `Persistence.mounts` parameters.
### Persistence Values
| Parameter | Description | Default |
| --------------------------- | ------------------------------- | --------------- |
| `Persistence.Enabled` | Enable the use of a Jenkins PVC | `true` |
| `Persistence.ExistingClaim` | Provide the name of a PVC | `nil` |
| `Persistence.AccessMode` | The PVC access mode | `ReadWriteOnce` |
| `Persistence.Size` | The size of the PVC | `8Gi` |
| `Persistence.volumes` | Additional volumes | `nil` |
| `Persistence.mounts` | Additional mounts | `nil` |
#### Existing PersistentVolumeClaim
1. Create the PersistentVolume
1. Create the PersistentVolumeClaim
1. Install the chart
```bash
$ helm install --name my-release --set Persistence.ExistingClaim=PVC_NAME stable/jenkins
```
## Custom ConfigMap
When creating a new parent chart with this chart as a dependency, the `CustomConfigMap` parameter can be used to override the default config.xml provided.
It also allows for providing additional xml configuration files that will be copied into `/var/jenkins_home`. In the parent chart's values.yaml,
set the `jenkins.Master.CustomConfigMap` value to true like so
```yaml
jenkins:
Master:
CustomConfigMap: true
```
and provide the file `templates/config.tpl` in your parent chart for your use case. You can start by copying the contents of `config.yaml` from this chart into your parent charts `templates/config.tpl` as a basis for customization. Finally, you'll need to wrap the contents of `templates/config.tpl` like so:
```yaml
{{- define "override_config_map" }}
<CONTENTS_HERE>
{{ end }}
```
## RBAC
If running upon a cluster with RBAC enabled you will need to do the following:
* `helm install stable/jenkins --set rbac.install=true`
* Create a Jenkins credential of type Kubernetes service account with service account name provided in the `helm status` output.
* Under configure Jenkins -- Update the credentials config in the cloud section to use the service account credential you created in the step above.
## Run Jenkins as non root user
The default settings of this helm chart let Jenkins run as root user with uid `0`.
Due to security reasons you may want to run Jenkins as a non root user.
Fortunately the default jenkins docker image `jenkins/jenkins` contains a user `jenkins` with uid `1000` that can be used for this purpose.
Simply use the following settings to run Jenkins as `jenkins` user with uid `1000`.
```yaml
jenkins:
Master:
RunAsUser: 1000
FsGroup: 1000
```
Docs taken from https://github.com/jenkinsci/docker/blob/master/Dockerfile:
_Jenkins is run with user `jenkins`, uid = 1000. If you bind mount a volume from the host or a data container,ensure you use the same uid_
## Running behind a forward proxy
The master pod uses an Init Container to install plugins etc. If you are behind a corporate proxy it may be useful to set `Master.InitContainerEnv` to add environment variables such as `http_proxy`, so that these can be downloaded.
Additionally, you may want to add env vars for the Jenkins container, and the JVM (`Master.JavaOpts`).
```yaml
Master:
InitContainerEnv:
- name: http_proxy
value: "http://192.168.64.1:3128"
- name: https_proxy
value: "http://192.168.64.1:3128"
- name: no_proxy
value: ""
ContainerEnv:
- name: http_proxy
value: "http://192.168.64.1:3128"
- name: https_proxy
value: "http://192.168.64.1:3128"
JavaOpts: >-
-Dhttp.proxyHost=192.168.64.1
-Dhttp.proxyPort=3128
-Dhttps.proxyHost=192.168.64.1
-Dhttps.proxyPort=3128
```

View File

@ -0,0 +1,6 @@
To be able to run helm inside a jenkins pod, you'll need to
* create a role in the namespace where tiller is installed
* bind that role to the user that jenkins pods run as
This directory contains yaml for these resources.
See also https://github.com/helm/helm/blob/master/docs/rbac.md

View File

@ -0,0 +1,13 @@
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: RoleBinding
metadata:
name: tiller-jenkins-binding
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: tiller-user
subjects:
- kind: ServiceAccount
name: default
namespace: molgenis-jenkins

View File

@ -0,0 +1,18 @@
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: tiller-user
namespace: kube-system
rules:
- apiGroups:
- ""
resources:
- pods/portforward
verbs:
- create
- apiGroups:
- ""
resources:
- pods
verbs:
- list

View File

@ -15,162 +15,126 @@ data:
<authorizationStrategy class="hudson.security.FullControlOnceLoggedInAuthorizationStrategy">
<denyAnonymousReadAccess>true</denyAnonymousReadAccess>
</authorizationStrategy>
{{- if .Values.Master.Security.UseGitHub }}
<securityRealm class="org.jenkinsci.plugins.GithubSecurityRealm">
<githubWebUri>https://github.com</githubWebUri>
<githubApiUri>https://api.github.com</githubApiUri>
<clientID>{{ .Values.Master.Security.GitHub.ClientID }}</clientID>
<clientSecret>{{ .Values.Master.Security.GitHub.ClientSecret }}</clientSecret>
<oauthScopes>read:org,user:email</oauthScopes>
</securityRealm>
{{- else }}
<securityRealm class="hudson.security.LegacySecurityRealm"/>
{{- end }}
<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/>
<primaryView>dev</primaryView>
<viewsTabBar class="hudson.views.DefaultViewsTabBar"/>
<myViewsTabBar class="hudson.views.DefaultMyViewsTabBar"/>
<clouds>
<org.csanchez.jenkins.plugins.kubernetes.KubernetesCloud plugin="kubernetes@{{ template "jenkins.kubernetes-version" . }}">
<name>kubernetes</name>
<templates>
{{- if .Values.Agent.Enabled }}
{{- range $podName, $pod := .Values.Pods }}
<org.csanchez.jenkins.plugins.kubernetes.PodTemplate>
<inheritFrom></inheritFrom>
<name>default</name>
<inheritFrom>{{ $pod.InheritFrom | default "" }}</inheritFrom>
<name>{{ $podName }}</name>
<instanceCap>2147483647</instanceCap>
<idleMinutes>0</idleMinutes>
<label>{{ .Release.Name }}-{{ .Values.Agent.Component }}</label>
<label>{{ .Label }}</label>
<nodeSelector>
{{- $local := dict "first" true }}
{{- range $key, $value := .Values.Agent.NodeSelector }}
{{- range $key, $value := .NodeSelector }}
{{- if not $local.first }},{{- end }}
{{- $key }}={{ $value }}
{{- $_ := set $local "first" false }}
{{- end }}</nodeSelector>
<nodeUsageMode>EXCLUSIVE</nodeUsageMode>
<nodeUsageMode>{{ .NodeUsageMode }}</nodeUsageMode>
<volumes>
{{- range $index, $volume := .Values.Agent.volumes }}
<org.csanchez.jenkins.plugins.kubernetes.volumes.{{ $volume.type }}Volume>
{{- range $index, $volume := .volumes }}
<org.csanchez.jenkins.plugins.kubernetes.volumes.{{ .type }}Volume>
{{- range $key, $value := $volume }}{{- if not (eq $key "type") }}
<{{ $key }}>{{ $value }}</{{ $key }}>
{{- end }}{{- end }}
</org.csanchez.jenkins.plugins.kubernetes.volumes.{{ $volume.type }}Volume>
</org.csanchez.jenkins.plugins.kubernetes.volumes.{{ .type }}Volume>
{{- end }}
</volumes>
<containers>
{{- range $containerName, $container := .Containers }}
<org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate>
<name>jnlp</name>
<image>{{ .Values.Agent.Image }}:{{ .Values.Agent.ImageTag }}</image>
{{- if .Values.Agent.Privileged }}
<name>{{ $containerName }}</name>
<image>{{ .Image }}:{{ .ImageTag | default "latest" }}</image>
<ports>
{{- range $index, $envVar := .Ports }}
<org.csanchez.jenkins.plugins.kubernetes.PortMapping>
<name>{{ .name }}</name>
<containerPort>{{ .containerPort }}</containerPort>
<hostPort>{{ .hostPort }}</hostPort>
</org.csanchez.jenkins.plugins.kubernetes.PortMapping>
{{- end }}
</ports>
{{- if .Privileged }}
<privileged>true</privileged>
{{- else }}
<privileged>false</privileged>
{{- end }}
<alwaysPullImage>{{ .Values.Agent.AlwaysPullImage }}</alwaysPullImage>
<workingDir>/home/jenkins</workingDir>
<command></command>
<args>${computer.jnlpmac} ${computer.name}</args>
<ttyEnabled>false</ttyEnabled>
<resourceRequestCpu>{{.Values.Agent.Cpu}}</resourceRequestCpu>
<resourceRequestMemory>{{.Values.Agent.Memory}}</resourceRequestMemory>
<resourceLimitCpu>{{.Values.Agent.Cpu}}</resourceLimitCpu>
<resourceLimitMemory>{{.Values.Agent.Memory}}</resourceLimitMemory>
<envVars>
<org.csanchez.jenkins.plugins.kubernetes.ContainerEnvVar>
<key>JENKINS_URL</key>
<value>http://{{ template "jenkins.fullname" . }}:{{.Values.Master.ServicePort}}{{ default "" .Values.Master.JenkinsUriPrefix }}</value>
</org.csanchez.jenkins.plugins.kubernetes.ContainerEnvVar>
</envVars>
</org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate>
</containers>
<envVars/>
<annotations/>
{{- if .Values.Agent.ImagePullSecret }}
<imagePullSecrets>
<org.csanchez.jenkins.plugins.kubernetes.PodImagePullSecret>
<name>{{ .Values.Agent.ImagePullSecret }}</name>
</org.csanchez.jenkins.plugins.kubernetes.PodImagePullSecret>
</imagePullSecrets>
{{- if .AlwaysPullImage }}
<alwaysPullImage>true</alwaysPullImage>
{{- else }}
<imagePullSecrets/>
<alwaysPullImage>false</alwaysPullImage>
{{- end }}
<nodeProperties/>
</org.csanchez.jenkins.plugins.kubernetes.PodTemplate>
{{- end -}}
{{- if .Values.Pod.Enabled }}
<org.csanchez.jenkins.plugins.kubernetes.PodTemplate>
<inheritFrom></inheritFrom>
<name>{{ .Values.Pod.Label }}</name>
<instanceCap>2147483647</instanceCap>
<idleMinutes>0</idleMinutes>
<label>{{ .Values.Pod.Label }}</label>
<nodeSelector>
{{- $local := dict "first" true }}
{{- range $key, $value := .Values.Pod.NodeSelector }}
{{- if not $local.first }},{{- end }}
{{- $key }}={{ $value }}
{{- $_ := set $local "first" false }}
{{- end }}</nodeSelector>
<nodeUsageMode>NORMAL</nodeUsageMode>
<volumes>
{{- range $index, $volume := .Values.Pod.volumes }}
<org.csanchez.jenkins.plugins.kubernetes.volumes.{{ $volume.type }}Volume>
{{- range $key, $value := $volume }}{{- if not (eq $key "type") }}
<{{ $key }}>{{ $value }}</{{ $key }}>
{{- end }}{{- end }}
</org.csanchez.jenkins.plugins.kubernetes.volumes.{{ $volume.type }}Volume>
{{- end }}
</volumes>
<containers>
<org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate>
<name>{{ .Values.Pod.Label }}</name>
<image>{{ .Values.Pod.Image }}:{{ .Values.Pod.ImageTag }}</image>
{{- if .Values.Pod.Privileged }}
<privileged>true</privileged>
{{- else }}
<privileged>false</privileged>
{{- end }}
<alwaysPullImage>{{ .Values.Pod.AlwaysPullImage }}</alwaysPullImage>
<workingDir>/home/jenkins</workingDir>
<command>{{ .Values.Pod.Command }}</command>
<args>{{ .Values.Pod.Args }}</args>
{{- if .Values.Pod.TTY }}
<workingDir>{{ .WorkingDir | default "" }}</workingDir>
<command>{{ .Command | default "" }}</command>
<args>{{ .Args | default "" }}</args>
{{- if .TTY }}
<ttyEnabled>true</ttyEnabled>
{{- else }}
<ttyEnabled>false</ttyEnabled>
{{- end }}
<resourceRequestCpu>{{.Values.Pod.Cpu}}</resourceRequestCpu>
<resourceRequestMemory>{{.Values.Pod.Memory}}</resourceRequestMemory>
<resourceLimitCpu>{{.Values.Pod.Cpu}}</resourceLimitCpu>
<resourceLimitMemory>{{.Values.Pod.Memory}}</resourceLimitMemory>
<envVars>
{{- range $index, $envVar := .EnvVars }}
<org.csanchez.jenkins.plugins.kubernetes.model.{{ .type }}EnvVar>
{{- range $key, $value := $envVar }}{{- if not (eq $key "type") }}
<{{ $key }}>{{ $value }}</{{ $key }}>
{{- end }}{{- end }}
</org.csanchez.jenkins.plugins.kubernetes.model.{{ .type }}EnvVar>
{{- end }}
</envVars>
{{- if .resources }}
{{- if .resources.requests }}
<resourceRequestCpu>{{ .resources.requests.cpu | default "" }}</resourceRequestCpu>
<resourceRequestMemory>{{ .resources.requests.memory | default "" }}</resourceRequestMemory>
{{- end }}
{{- if .resources.limits }}
<resourceLimitCpu>{{ .resources.limits.cpu | default "" }}</resourceLimitCpu>
<resourceLimitMemory>{{ .resources.limits.memory | default "" }}</resourceLimitMemory>
{{- end }}
{{- end }}
</org.csanchez.jenkins.plugins.kubernetes.ContainerTemplate>
{{- end }}
</containers>
<envVars>
<org.csanchez.jenkins.plugins.kubernetes.model.SecretEnvVar>
<key>PGP_PASSPHRASE</key>
<secretName>molgenis-pipeline-env-secret</secretName>
<secretKey>pgpPassphrase</secretKey>
</org.csanchez.jenkins.plugins.kubernetes.model.SecretEnvVar>
<org.csanchez.jenkins.plugins.kubernetes.model.KeyValueEnvVar>
<key>PGP_SECRETKEY</key>
<value>keyfile:/root/.m2/key.asc</value>
</org.csanchez.jenkins.plugins.kubernetes.model.KeyValueEnvVar>
<org.csanchez.jenkins.plugins.kubernetes.model.SecretEnvVar>
<key>SONAR_TOKEN</key>
<secretName>molgenis-pipeline-env-secret</secretName>
<secretKey>sonarToken</secretKey>
</org.csanchez.jenkins.plugins.kubernetes.model.SecretEnvVar>
<org.csanchez.jenkins.plugins.kubernetes.model.SecretEnvVar>
<key>CODECOV_TOKEN</key>
<secretName>molgenis-pipeline-env-secret</secretName>
<secretKey>codecovToken</secretKey>
</org.csanchez.jenkins.plugins.kubernetes.model.SecretEnvVar>
<org.csanchez.jenkins.plugins.kubernetes.model.SecretEnvVar>
<key>GITHUB_TOKEN</key>
<secretName>molgenis-pipeline-env-secret</secretName>
<secretKey>githubToken</secretKey>
</org.csanchez.jenkins.plugins.kubernetes.model.SecretEnvVar>
<org.csanchez.jenkins.plugins.kubernetes.model.KeyValueEnvVar>
<key>JENKINS_URL</key>
<value>http://{{ template "jenkins.fullname" $ }}:{{$.Values.Master.ServicePort}}{{ default "" $.Values.Master.JenkinsUriPrefix }}</value>
</org.csanchez.jenkins.plugins.kubernetes.model.KeyValueEnvVar>
{{- range $index, $envVar := .EnvVars }}
<org.csanchez.jenkins.plugins.kubernetes.model.{{ .type }}EnvVar>
{{- range $key, $value := $envVar }}{{- if not (eq $key "type") }}
<{{ $key }}>{{ $value }}</{{ $key }}>
{{- end }}{{- end }}
</org.csanchez.jenkins.plugins.kubernetes.model.{{ .type }}EnvVar>
{{- end }}
</envVars>
<annotations/>
{{- if .Values.Pod.ImagePullSecret }}
{{- if .ImagePullSecret }}
<imagePullSecrets>
<org.csanchez.jenkins.plugins.kubernetes.PodImagePullSecret>
<name>{{ .Values.Pod.ImagePullSecret }}</name>
<name>{{ .ImagePullSecret }}</name>
</org.csanchez.jenkins.plugins.kubernetes.PodImagePullSecret>
</imagePullSecrets>
{{- else }}
@ -178,14 +142,14 @@ data:
{{- end }}
<nodeProperties/>
</org.csanchez.jenkins.plugins.kubernetes.PodTemplate>
{{- end -}}
{{- end }}
</templates>
<serverUrl>https://kubernetes.default</serverUrl>
<skipTlsVerify>false</skipTlsVerify>
<namespace>{{ .Release.Namespace }}</namespace>
<jenkinsUrl>http://{{ template "jenkins.fullname" . }}:{{.Values.Master.ServicePort}}{{ default "" .Values.Master.JenkinsUriPrefix }}</jenkinsUrl>
<jenkinsTunnel>{{ template "jenkins.fullname" . }}-agent:50000</jenkinsTunnel>
<containerCap>10</containerCap>
<containerCap>50</containerCap>
<retentionTimeout>5</retentionTimeout>
<connectTimeout>0</connectTimeout>
<readTimeout>0</readTimeout>
@ -196,13 +160,40 @@ data:
<views>
<hudson.model.AllView>
<owner class="hudson" reference="../../.."/>
<name>All</name>
<name>all</name>
<filterExecutors>false</filterExecutors>
<filterQueue>false</filterQueue>
<properties class="hudson.model.View$PropertyList"/>
</hudson.model.AllView>
{{- range $viewName, $view := .Values.Master.Views }}
<listView>
<owner class="hudson" reference="../../.."/>
<name>{{ $viewName }}</name>
<filterExecutors>false</filterExecutors>
<filterQueue>false</filterQueue>
<properties class="hudson.model.View$PropertyList"/>
<jobNames>
<comparator class="hudson.util.CaseInsensitiveComparator" reference="../../../listView/jobNames/comparator"/>
{{- range $index, $job := $view }}
<string>{{ $job }}</string>
{{- end }}
</jobNames>
<jobFilters/>
<columns>
<hudson.views.StatusColumn/>
<hudson.views.WeatherColumn/>
<hudson.views.JobColumn/>
<hudson.views.LastSuccessColumn/>
<hudson.views.LastFailureColumn/>
<hudson.views.LastDurationColumn/>
<hudson.views.BuildButtonColumn/>
<hudson.plugins.favorite.column.FavoriteColumn plugin="favorite@2.3.2"/>
</columns>
<recurse>false</recurse>
</listView>
{{- end }}
</views>
<primaryView>All</primaryView>
<primaryView>{{ .Values.Master.DefaultView }}</primaryView>
<slaveAgentPort>50000</slaveAgentPort>
<disabledAgentProtocols>
{{- range .Values.Master.DisabledAgentProtocols }}

View File

@ -0,0 +1,16 @@
apiVersion: v1
kind: Secret
metadata:
# this is the jenkins id.
name: "molgenis-jenkins-dockerhub-secret"
labels:
# so we know what type it is.
"jenkins.io/credentials-type": "usernamePassword"
annotations: {
# description - can not be a label as spaces are not allowed
"jenkins.io/credentials-description" : "(deprecated by vault) Account used in pipeline builds to push docker images to Docker Hub (hub.docker.com)"
}
type: Opaque
data:
username: {{ .Values.secret.registry.user | b64enc | quote }}
password: {{ .Values.secret.registry.password | b64enc | quote }}

View File

@ -0,0 +1,16 @@
apiVersion: v1
kind: Secret
metadata:
# this is the jenkins id.
name: "molgenis-jenkins-github-secret"
labels:
# so we know what type it is.
"jenkins.io/credentials-type": "usernamePassword"
annotations: {
# description - can not be a label as spaces are not allowed
"jenkins.io/credentials-description" : "Oauth token for the {{.Values.secret.gitHub.user}} GitHub user"
}
type: Opaque
data:
username: {{ .Values.secret.gitHub.user | b64enc | quote }}
password: {{ .Values.secret.gitHub.token | b64enc | quote }}

View File

@ -0,0 +1,16 @@
apiVersion: v1
kind: Secret
metadata:
# this is the jenkins id.
name: "molgenis-jenkins-gogs-secret"
labels:
# so we know what type it is.
"jenkins.io/credentials-type": "usernamePassword"
annotations: {
# description - can not be a label as spaces are not allowed
"jenkins.io/credentials-description" : "Account used to authenticate against RuG Webhosting Gogs."
}
type: Opaque
data:
username: {{ .Values.secret.gogs.user | b64enc | quote }}
password: {{ .Values.secret.gogs.token | b64enc | quote }}

View File

@ -0,0 +1,17 @@
apiVersion: v1
kind: Secret
metadata:
name: molgenis-jenkins-registry-secret
labels:
app: {{ template "jenkins.fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
annotations: {
# description - can not be a label as spaces are not allowed
"jenkins.io/credentials-description" : "(deprecated by vault) Account used in pipeline builds to push docker images to registry.molgenis.org."
}
type: Opaque
data:
username: {{ .Values.secret.registry.user | b64enc | quote }}
password: {{ .Values.secret.registry.password | b64enc | quote }}

View File

@ -1,17 +0,0 @@
{{- if .Values.PipelineSecrets.Env.Replace }}
apiVersion: v1
kind: Secret
metadata:
name: molgenis-pipeline-env-secret
labels:
app: {{ template "jenkins.fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
type: Opaque
data:
pgpPassphrase: {{ .Values.PipelineSecrets.Env.PGPPassphrase | b64enc | quote }}
codecovToken: {{ .Values.PipelineSecrets.Env.CodecovToken | b64enc | quote }}
githubToken: {{ .Values.PipelineSecrets.Env.GithubToken | b64enc | quote }}
sonarToken: {{ .Values.PipelineSecrets.Env.SonarToken | b64enc | quote }}
{{- end }}

View File

@ -1,15 +0,0 @@
{{- if .Values.PipelineSecrets.File.Replace }}
apiVersion: v1
kind: Secret
metadata:
name: molgenis-pipeline-env-secret
labels:
app: {{ template "jenkins.fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
type: Opaque
data:
maven.xml: {{ .Values.PipelineSecrets.File.MavenSettingsXML | b64enc | quote }}
key.asc: {{ .Values.PipelineSecrets.File.PGPPrivateKeyAsc | b64enc | quote }}
{{- end }}

View File

@ -0,0 +1,14 @@
apiVersion: v1
kind: Secret
metadata:
name: molgenis-pipeline-vault-secret
labels:
app: {{ template "jenkins.fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
type: Opaque
data:
token: {{ .Values.secret.vault.token | b64enc | quote }}
addr: {{ .Values.secret.vault.addr | b64enc | quote }}
skipVerify: {{ .Values.secret.vault.skipVerify | b64enc | quote }}

View File

@ -3,63 +3,359 @@ jenkins:
HostName: jenkins.molgenis.org
ServiceType: ClusterIP
InstallPlugins:
- kubernetes:1.8.4
- kubernetes:1.12.0
- workflow-aggregator:2.5
- workflow-job:2.21
- credentials-binding:1.16
- git:3.9.1
- github-branch-source:2.3.6
- kubernetes-credentials-provider:0.9
- blueocean:1.6.2
- github-oauth:0.29
- gogs-webhook:1.0.14
- sauce-ondemand:1.176
Security:
UseGitHub: false
GitHub:
ClientID: ""
ClienSecret: ""
DefaultView: dev
Views:
dev:
- molgenis
ops:
- molgenis-ops-docker-httpd
- molgenis-ops-docker-maven
- molgenis-ops-docker-node
- molgenis-ops-tools
- molgenis-ops-tomcat
Jobs: |-
molgenis: |-
<?xml version='1.1' encoding='UTF-8'?>
<jenkins.branch.OrganizationFolder plugin="branch-api@2.0.20">
<actions/>
<description></description>
<properties>
<org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig plugin="pipeline-model-definition@1.3.1">
<dockerLabel></dockerLabel>
<registry plugin="docker-commons@1.13"/>
</org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig>
<jenkins.branch.NoTriggerOrganizationFolderProperty>
<branches>.*</branches>
</jenkins.branch.NoTriggerOrganizationFolderProperty>
</properties>
<folderViews class="jenkins.branch.OrganizationFolderViewHolder">
<owner reference="../.."/>
</folderViews>
<healthMetrics>
<com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric plugin="cloudbees-folder@6.5.1">
<nonRecursive>false</nonRecursive>
</com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric>
</healthMetrics>
<icon class="jenkins.branch.MetadataActionFolderIcon">
<owner class="jenkins.branch.OrganizationFolder" reference="../.."/>
</icon>
<orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder@6.5.1">
<pruneDeadBranches>true</pruneDeadBranches>
<daysToKeep>-1</daysToKeep>
<numToKeep>-1</numToKeep>
</orphanedItemStrategy>
<triggers>
<com.cloudbees.hudson.plugins.folder.computed.PeriodicFolderTrigger plugin="cloudbees-folder@6.5.1">
<spec>H H * * *</spec>
<interval>86400000</interval>
</com.cloudbees.hudson.plugins.folder.computed.PeriodicFolderTrigger>
</triggers>
<disabled>false</disabled>
<navigators>
<org.jenkinsci.plugins.github__branch__source.GitHubSCMNavigator plugin="github-branch-source@2.3.6">
<repoOwner>molgenis</repoOwner>
<credentialsId>molgenis-jenkins-github-secret</credentialsId>
<traits>
<org.jenkinsci.plugins.github__branch__source.BranchDiscoveryTrait>
<strategyId>1</strategyId>
</org.jenkinsci.plugins.github__branch__source.BranchDiscoveryTrait>
<org.jenkinsci.plugins.github__branch__source.OriginPullRequestDiscoveryTrait>
<strategyId>1</strategyId>
</org.jenkinsci.plugins.github__branch__source.OriginPullRequestDiscoveryTrait>
<org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait>
<strategyId>1</strategyId>
<trust class="org.jenkinsci.plugins.github_branch_source.ForkPullRequestDiscoveryTrait$TrustPermission"/>
</org.jenkinsci.plugins.github__branch__source.ForkPullRequestDiscoveryTrait>
</traits>
</org.jenkinsci.plugins.github__branch__source.GitHubSCMNavigator>
</navigators>
<projectFactories>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProjectFactory plugin="workflow-multibranch@2.19">
<scriptPath>Jenkinsfile</scriptPath>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProjectFactory>
</projectFactories>
<buildStrategies/>
</jenkins.branch.OrganizationFolder>
molgenis-ops-docker-httpd: |-
<?xml version='1.1' encoding='UTF-8'?>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject plugin="workflow-multibranch@2.19">
<actions/>
<description></description>
<properties>
<org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig plugin="pipeline-model-definition@1.3">
<dockerLabel></dockerLabel>
<registry plugin="docker-commons@1.13"/>
</org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig>
</properties>
<folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api@2.0.20">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</folderViews>
<healthMetrics>
<com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric plugin="cloudbees-folder@6.5.1">
<nonRecursive>false</nonRecursive>
</com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric>
</healthMetrics>
<icon class="jenkins.branch.MetadataActionFolderIcon" plugin="branch-api@2.0.20">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</icon>
<orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder@6.5.1">
<pruneDeadBranches>true</pruneDeadBranches>
<daysToKeep>-1</daysToKeep>
<numToKeep>-1</numToKeep>
</orphanedItemStrategy>
<triggers/>
<disabled>false</disabled>
<sources class="jenkins.branch.MultiBranchProject$BranchSourceList" plugin="branch-api@2.0.20">
<data>
<jenkins.branch.BranchSource>
<source class="jenkins.plugins.git.GitSCMSource" plugin="git@3.9.1">
<id>a1f535cd-ab83-4d42-8993-0c3e59cf139f</id>
<remote>http://github.com/molgenis/molgenis.git</remote>
<credentialsId></credentialsId>
<traits>
<jenkins.plugins.git.traits.BranchDiscoveryTrait/>
</traits>
</source>
<strategy class="jenkins.branch.DefaultBranchPropertyStrategy">
<properties class="empty-list"/>
</strategy>
</jenkins.branch.BranchSource>
</data>
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</sources>
<factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
</factory>
<actions/>
<description>HTTPD server that can be used for redirection and proxieing</description>
<displayName>molgenis-ops-docker-httpd</displayName>
<properties>
<org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig plugin="pipeline-model-definition@1.3.1">
<dockerLabel></dockerLabel>
<registry plugin="docker-commons@1.13"/>
</org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig>
</properties>
<folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api@2.0.20">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</folderViews>
<healthMetrics>
<com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric plugin="cloudbees-folder@6.5.1">
<nonRecursive>false</nonRecursive>
</com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric>
</healthMetrics>
<icon class="jenkins.branch.MetadataActionFolderIcon" plugin="branch-api@2.0.20">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</icon>
<orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder@6.5.1">
<pruneDeadBranches>true</pruneDeadBranches>
<daysToKeep>-1</daysToKeep>
<numToKeep>-1</numToKeep>
</orphanedItemStrategy>
<triggers/>
<disabled>false</disabled>
<sources class="jenkins.branch.MultiBranchProject$BranchSourceList" plugin="branch-api@2.0.20">
<data>
<jenkins.branch.BranchSource>
<source class="jenkins.plugins.git.GitSCMSource" plugin="git@3.9.1">
<id>a756941d-6c9d-4492-bcf9-327041764be6</id>
<remote>https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-httpd.git</remote>
<credentialsId>molgenis-jenkins-gogs-secret</credentialsId>
<traits>
<jenkins.plugins.git.traits.BranchDiscoveryTrait/>
</traits>
</source>
<strategy class="jenkins.branch.DefaultBranchPropertyStrategy">
<properties class="empty-list"/>
</strategy>
</jenkins.branch.BranchSource>
</data>
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</sources>
<factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
</factory>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>
molgenis-ops-docker-node: |-
<?xml version='1.1' encoding='UTF-8'?>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject plugin="workflow-multibranch@2.19">
<actions/>
<description>NodeJS build container with Curl</description>
<displayName>molgenis-ops-docker-node</displayName>
<properties>
<org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig plugin="pipeline-model-definition@1.3.1">
<dockerLabel></dockerLabel>
<registry plugin="docker-commons@1.13"/>
</org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig>
</properties>
<folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api@2.0.20">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</folderViews>
<healthMetrics>
<com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric plugin="cloudbees-folder@6.5.1">
<nonRecursive>false</nonRecursive>
</com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric>
</healthMetrics>
<icon class="jenkins.branch.MetadataActionFolderIcon" plugin="branch-api@2.0.20">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</icon>
<orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder@6.5.1">
<pruneDeadBranches>true</pruneDeadBranches>
<daysToKeep>-1</daysToKeep>
<numToKeep>-1</numToKeep>
</orphanedItemStrategy>
<triggers/>
<disabled>false</disabled>
<sources class="jenkins.branch.MultiBranchProject$BranchSourceList" plugin="branch-api@2.0.20">
<data>
<jenkins.branch.BranchSource>
<source class="jenkins.plugins.git.GitSCMSource" plugin="git@3.9.1">
<id>a756941d-6c9d-4492-bcf9-327041764be6</id>
<remote>https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-node.git</remote>
<credentialsId>molgenis-jenkins-gogs-secret</credentialsId>
<traits>
<jenkins.plugins.git.traits.BranchDiscoveryTrait/>
</traits>
</source>
<strategy class="jenkins.branch.DefaultBranchPropertyStrategy">
<properties class="empty-list"/>
</strategy>
</jenkins.branch.BranchSource>
</data>
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</sources>
<factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
</factory>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>
molgenis-ops-docker-maven: |-
<?xml version='1.1' encoding='UTF-8'?>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject plugin="workflow-multibranch@2.19">
<actions/>
<description>MAVEN build container with RPMbuild and Curl</description>
<displayName>molgenis-ops-docker-maven</displayName>
<properties>
<org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig plugin="pipeline-model-definition@1.3.1">
<dockerLabel></dockerLabel>
<registry plugin="docker-commons@1.13"/>
</org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig>
</properties>
<folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api@2.0.20">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</folderViews>
<healthMetrics>
<com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric plugin="cloudbees-folder@6.5.1">
<nonRecursive>false</nonRecursive>
</com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric>
</healthMetrics>
<icon class="jenkins.branch.MetadataActionFolderIcon" plugin="branch-api@2.0.20">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</icon>
<orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder@6.5.1">
<pruneDeadBranches>true</pruneDeadBranches>
<daysToKeep>-1</daysToKeep>
<numToKeep>-1</numToKeep>
</orphanedItemStrategy>
<triggers/>
<disabled>false</disabled>
<sources class="jenkins.branch.MultiBranchProject$BranchSourceList" plugin="branch-api@2.0.20">
<data>
<jenkins.branch.BranchSource>
<source class="jenkins.plugins.git.GitSCMSource" plugin="git@3.9.1">
<id>4702479a-6988-4a85-b4b7-e77fa2d05ffa</id>
<remote>https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-maven.git</remote>
<credentialsId>molgenis-jenkins-gogs-secret</credentialsId>
<traits>
<jenkins.plugins.git.traits.BranchDiscoveryTrait/>
</traits>
</source>
<strategy class="jenkins.branch.DefaultBranchPropertyStrategy">
<properties class="empty-list"/>
</strategy>
</jenkins.branch.BranchSource>
</data>
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</sources>
<factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
</factory>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>
molgenis-ops-tomcat: |-
<?xml version='1.1' encoding='UTF-8'?>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject plugin="workflow-multibranch@2.19">
<actions/>
<description>MOLGENIS tomcat package to manage tomcat version on CentOS</description>
<displayName>molgenis-ops-tomcat</displayName>
<properties>
<org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig plugin="pipeline-model-definition@1.3.1">
<dockerLabel></dockerLabel>
<registry plugin="docker-commons@1.13"/>
</org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig>
</properties>
<folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api@2.0.20">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</folderViews>
<healthMetrics>
<com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric plugin="cloudbees-folder@6.5.1">
<nonRecursive>false</nonRecursive>
</com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric>
</healthMetrics>
<icon class="jenkins.branch.MetadataActionFolderIcon" plugin="branch-api@2.0.20">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</icon>
<orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder@6.5.1">
<pruneDeadBranches>true</pruneDeadBranches>
<daysToKeep>-1</daysToKeep>
<numToKeep>-1</numToKeep>
</orphanedItemStrategy>
<triggers/>
<disabled>false</disabled>
<sources class="jenkins.branch.MultiBranchProject$BranchSourceList" plugin="branch-api@2.0.20">
<data>
<jenkins.branch.BranchSource>
<source class="jenkins.plugins.git.GitSCMSource" plugin="git@3.9.1">
<id>4702479a-6988-4a85-b4b7-e77fa2d05ffa</id>
<remote>https://git.webhosting.rug.nl/molgenis/molgenis-ops-tomcat.git</remote>
<credentialsId>molgenis-jenkins-gogs-secret</credentialsId>
<traits>
<jenkins.plugins.git.traits.BranchDiscoveryTrait/>
</traits>
</source>
<strategy class="jenkins.branch.DefaultBranchPropertyStrategy">
<properties class="empty-list"/>
</strategy>
</jenkins.branch.BranchSource>
</data>
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</sources>
<factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
</factory>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>
molgenis-ops-tools: |-
<?xml version='1.1' encoding='UTF-8'?>
<org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject plugin="workflow-multibranch@2.19">
<actions/>
<description>MOLGENIS operations tools-package to configure firewall, apache, sudoers, etc.</description>
<displayName>molgenis-ops-tools</displayName>
<properties>
<org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig plugin="pipeline-model-definition@1.3.1">
<dockerLabel></dockerLabel>
<registry plugin="docker-commons@1.13"/>
</org.jenkinsci.plugins.pipeline.modeldefinition.config.FolderConfig>
</properties>
<folderViews class="jenkins.branch.MultiBranchProjectViewHolder" plugin="branch-api@2.0.20">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</folderViews>
<healthMetrics>
<com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric plugin="cloudbees-folder@6.5.1">
<nonRecursive>false</nonRecursive>
</com.cloudbees.hudson.plugins.folder.health.WorstChildHealthMetric>
</healthMetrics>
<icon class="jenkins.branch.MetadataActionFolderIcon" plugin="branch-api@2.0.20">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</icon>
<orphanedItemStrategy class="com.cloudbees.hudson.plugins.folder.computed.DefaultOrphanedItemStrategy" plugin="cloudbees-folder@6.5.1">
<pruneDeadBranches>true</pruneDeadBranches>
<daysToKeep>-1</daysToKeep>
<numToKeep>-1</numToKeep>
</orphanedItemStrategy>
<triggers/>
<disabled>false</disabled>
<sources class="jenkins.branch.MultiBranchProject$BranchSourceList" plugin="branch-api@2.0.20">
<data>
<jenkins.branch.BranchSource>
<source class="jenkins.plugins.git.GitSCMSource" plugin="git@3.9.1">
<id>4702479a-6988-4a85-b4b7-e77fa2d05ffa</id>
<remote>https://git.webhosting.rug.nl/molgenis/molgenis-ops-tools.git</remote>
<credentialsId>molgenis-jenkins-gogs-secret</credentialsId>
<traits>
<jenkins.plugins.git.traits.BranchDiscoveryTrait/>
</traits>
</source>
<strategy class="jenkins.branch.DefaultBranchPropertyStrategy">
<properties class="empty-list"/>
</strategy>
</jenkins.branch.BranchSource>
</data>
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
</sources>
<factory class="org.jenkinsci.plugins.workflow.multibranch.WorkflowBranchProjectFactory">
<owner class="org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject" reference="../.."/>
<scriptPath>Jenkinsfile</scriptPath>
</factory>
</org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject>
# Kubernetes secret that contains a 'credentials.xml' for Jenkins
# CredentialsXmlSecret: jenkins-credentials
@ -70,80 +366,176 @@ jenkins:
CustomConfigMap: true
rbac:
install: true
# A second pod template for maven builds
Pod:
Enabled: true
Image: "webhost12.service.rug.nl/molgenis/molgenis-maven"
ImageTag: latest
# ImagePullSecret: jenkins
Label: "molgenis-maven"
Privileged: false
Cpu: ""
Memory: ""
# You may want to change this to true while testing a new image
AlwaysPullImage: false
Command: "/bin/sh -c"
Args: "cat"
TTY: true
# You can define the volumes that you want to mount for this container
# Allowed types are: ConfigMap, EmptyDir, HostPath, Nfs, Pod, Secret
# Configure the attributes as they appear in the corresponding Java class for that type
# https://github.com/jenkinsci/kubernetes-plugin/tree/master/src/main/java/org/csanchez/jenkins/plugins/kubernetes/volumes
volumes:
- type: HostPath
hostPath: "/var/run/docker.sock"
mountPath: "/var/run/docker.sock"
- type: Secret
secretName: molgenis-pipeline-file-secret
mountPath: "keyfile:/root/.m2"
NodeSelector: {}
# Key Value selectors. Ex:
# jenkins-agent: v1
PipelineSecrets:
Env:
# Set to false to keep existing secret
Replace: true
# Passphrase for the pgp private key file
pgpPassphrase: xxxx
# Token for codecov.io service
codecovToken: xxxx
# Token for github bot account
githubToken: xxxx
# Token for sonarcloud.io
sonarToken: xxxx
File:
# Set to false to keep existing secret
Replace: true
# PGP Private key in ascii format used to sign artifacts
PGPPrivateKeyAsc: |-
-----BEGIN PGP PRIVATE KEY BLOCK-----
xxxxx
-----END PGP PRIVATE KEY BLOCK-----
# maven.settings file
MavenSettingsXML: |-
<settings>
<!-- sets the local maven repository outside of the ~/.m2 folder for easier mounting of secrets and repo -->
<localRepository>${user.home}/.mvnrepository</localRepository>
<!-- lets disable the download progress indicator that fills up logs -->
<interactiveMode>false</interactiveMode>
<mirrors>
<mirror>
<id>nexus</id>
<mirrorOf>external:*</mirrorOf>
<url>https://registry.molgenis.org/repository/maven-central/</url>
</mirror>
</mirrors>
<servers>
<server>
<id>local-nexus</id>
<url>https://registry.molgenis.org/repository/maven-central/</url>
<username>admin</username>
<password>xxxxx</password>
</server>
<server>
<id>oss-sonatype-staging</id>
<username>molgenis</username>
<password>xxxxx</password>
</server>
</servers>
</settings>
Pods:
molgenis:
Label: molgenis
NodeUsageMode: NORMAL
volumes:
- type: HostPath
hostPath: "/var/run/docker.sock"
mountPath: "/var/run/docker.sock"
Containers:
maven:
Image: "registry.webhosting.rug.nl/molgenis/maven"
ImageTag: lts
AlwaysPullImage: true
Command: cat
WorkingDir: /home/jenkins
TTY: true
resources:
requests:
cpu: "1"
memory: "4Gi"
EnvVars:
- type: KeyValue
key: MAVEN_OPTS
value: "-Duser.home=/home/jenkins"
- type: KeyValue
key: MAVEN_CONFIG
value: "/home/jenkins/.m2"
alpine:
Image: "spotify/alpine"
Command: cat
WorkingDir: /home/jenkins
TTY: true
vault:
Image: "vault"
Command: cat
WorkingDir: /home/jenkins
TTY: true
EnvVars:
- type: Secret
key: VAULT_TOKEN
secretName: molgenis-pipeline-vault-secret
secretKey: token
- type: Secret
key: VAULT_SKIP_VERIFY
secretName: molgenis-pipeline-vault-secret
secretKey: skipVerify
- type: Secret
key: VAULT_ADDR
secretName: molgenis-pipeline-vault-secret
secretKey: addr
helm:
Image: "lachlanevenson/k8s-helm"
ImageTag: "v2.10.0"
Command: cat
WorkingDir: /home/jenkins
TTY: true
NodeSelector: {}
node:
Label: node-carbon
NodeUsageMode: EXCLUSIVE
Containers:
node:
Image: "registry.webhosting.rug.nl/molgenis/node"
ImageTag: lts
AlwaysPullImage: true
Command: cat
WorkingDir: /home/jenkins
TTY: true
vault:
Image: "vault"
Command: cat
WorkingDir: /home/jenkins
TTY: true
EnvVars:
- type: Secret
key: VAULT_TOKEN
secretName: molgenis-pipeline-vault-secret
secretKey: token
- type: Secret
key: VAULT_SKIP_VERIFY
secretName: molgenis-pipeline-vault-secret
secretKey: skipVerify
- type: Secret
key: VAULT_ADDR
secretName: molgenis-pipeline-vault-secret
secretKey: addr
NodeSelector: {}
molgenis-it:
InheritFrom: molgenis
Label: molgenis-it
NodeUsageMode: EXCLUSIVE
Containers:
elasticsearch:
Image: docker.elastic.co/elasticsearch/elasticsearch
ImageTag: 5.5.3
resources:
requests:
cpu: "100m"
memory: "1Gi"
limits:
cpu: "1"
memory: "1500Mi"
EnvVars:
- type: KeyValue
key: ES_JAVA_OPTS
value: "-Xms512m -Xmx512m"
- type: KeyValue
key: cluster.name
value: molgenis
- type: KeyValue
key: bootstrap.memory_lock
value: "true"
- type: KeyValue
key: xpack.security.enabled
value: "false"
- type: KeyValue
key: discovery.type
value: single-node
postgres:
Image: postgres
ImageTag: 9.6-alpine
resources:
requests:
cpu: "100m"
memory: "250Mi"
limits:
cpu: "1"
memory: "250Mi"
EnvVars:
- type: KeyValue
key: POSTGRES_USER
value: molgenis
- type: KeyValue
key: POSTGRES_PASSWORD
value: molgenis
- type: KeyValue
key: POSTGRES_DB
value: molgenis
opencpu:
Image: molgenis/opencpu
AlwaysPullImage: true
resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "1"
memory: "512Mi"
NodeSelector: {}
#secret contains configuration for the kubernetes secrets that jenkins can access
secret:
# vault configures the vault secret
vault:
token: xxxx
addr: "https://vault-operator.vault-operator.svc:8200"
skipVerify: "1"
# githubToken contains access token for jenkins bot account on github.com
gitHub:
user: "molgenis-jenkins"
token: xxxx
# gogs contains access token for jenkins bot account on RuG GoGs
gogs:
user: p281392
token: xxxx
# registry contains credentials for registry.molgenis.org
registry:
user: admin
password: xxxx
# dockerHubPassword contains password for hub.docker.com
dockerHub:
user: molgenisci
password: xxxx

View File

@ -0,0 +1,8 @@
apiVersion: v1
appVersion: "1.0"
description: Nexus stack for MOLGENIS
name: molgenis-nexus
version: 0.3.0
sources:
- https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm.git
icon: https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm/raw/master/molgenis-nexus/catalogIcon-molgenis-nexus.svg

28
molgenis-nexus/README.md Normal file
View File

@ -0,0 +1,28 @@
# MOLGENIS - NEXUS Helm Chart
NEXUS repository for kubernetes to deploy on a kubernetes cluster with NFS-share
## Chart Details
This chart will deploy:
- 1 NEXUS container
- 1 MOLGENIS-httpd container ()to proxy the registry and docker to one domain)
## Installing the Chart
You can test in install the chart by executing:
```helm lint .```
To test if your helm chart-syntax is right and:
```helm install . --dry-run --debug```
To test if your hem chart works and:
```helm install .```
To deploy it on the cluster.

View File

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -20,17 +20,17 @@ spec:
creationTimestamp: null
spec:
volumes:
- name: molgenis-nexus-data
- name: {{ .Values.persistence.name }}
persistentVolumeClaim:
claimName: molgenis-nexus-data
claimName: {{ .Values.persistence.name }}
restartPolicy: {{ .Values.nexus.restartPolicy }}
initContainers:
- name: volume-mount-nexus
image: busybox
command: ["sh", "-c", "chown -R 200:200 /gcc/molgenis/nexus"]
command: ["sh", "-c", "chown -R 200:200 {{ .Values.persistence.mountPath }}"]
volumeMounts:
- name: molgenis-nexus-data
mountPath: "/nexus-data"
- name: {{ .Values.persistence.name }}
mountPath: "{{ .Values.persistence.mountPath }}"
containers:
- name: {{ .Values.nexus.name }}
image: "{{ .Values.nexus.image.repository }}:{{ .Values.nexus.image.tag }}"
@ -39,6 +39,6 @@ spec:
- containerPort: {{ .Values.nexus.port.ui }}
- containerPort: {{ .Values.nexus.port.docker }}
volumeMounts:
- name: molgenis-nexus-data
- name: {{ .Values.persistence.name }}
mountPath: "/nexus-data"

View File

@ -5,7 +5,7 @@ metadata:
labels:
app: {{ .Values.httpd.name }}
spec:
type: NodePort
type: {{ .Values.httpd.service.type }}
ports:
- name: {{ .Values.httpd.name }}
port: {{ .Values.httpd.port }}

View File

@ -5,7 +5,7 @@ metadata:
labels:
app: {{ .Values.nexus.name }}
spec:
type: ClusterIP
type: {{ .Values.nexus.service.type }}
ports:
- name: ui
port: {{ .Values.nexus.port.ui }}

View File

@ -0,0 +1,16 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: {{ .Values.persistence.name }}
labels:
name: nfs2
spec:
storageClassName: {{ .Values.persistence.storageClass }}
capacity:
storage: {{ .Values.persistence.size }}
accessModes:
- {{ .Values.persistence.accessMode }}
persistentVolumeReclaimPolicy: {{ .Values.persistence.reclaimPolicy }}
nfs:
server: {{ .Values.persistence.server }}
path: {{ .Values.persistence.mountPath }}

View File

@ -0,0 +1,11 @@
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: {{ .Values.persistence.name }}
spec:
storageClassName: {{ .Values.persistence.storageClass }}
accessModes:
- {{ .Values.persistence.accessMode }}
resources:
requests:
storage: {{ .Values.persistence.size }}

View File

@ -6,10 +6,6 @@ replicaCount: 1
environment: production
service:
type: NodePort
port: 80
nexus:
name: nexus
strategy:
@ -25,6 +21,8 @@ nexus:
ui: 8081
path:
dockerV2: v2
service:
type: ClusterIP
httpd:
name: httpd
@ -38,6 +36,8 @@ httpd:
tag: lts
pullPolicy: Always
port: 80
service:
type: LoadBalancer
ingress:
@ -53,6 +53,16 @@ ingress:
# hosts:
# - chart-example.local
persistence:
name: molgenis-nexus-data
storageClass: nfs-class
size: 30G
reclaimPolicy: Retain
server: 192.168.64.12
accessMode: ReadWriteMany
mountPath: /gcc/molgenis/nexus
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little

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

View File

@ -0,0 +1,8 @@
apiVersion: v1
appVersion: "1.0"
description: MOLGENIS - helm stack for testing purposes
name: molgenis-preview
version: 0.2.0
sources:
- https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm.git
icon: https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm/raw/master/molgenis-preview/catalogIcon-molgenis.svg

View File

@ -0,0 +1,16 @@
# MOLGENIS preview
This chart is used for testing purposes. It can be used by data managers or developers to test MOLGENIS (e.g. integration testing).
## Containers
This chart spins up a complete stack to run MOLGENIS. The created containers are:
- MOLGENIS
- PostgreSQL
- Elasticsearch
- OpenCPU
## Rancher
You can spin up a test instance by navigating to https://rancher.molgenis.org:7777 and login with your LDAP-account.
Go to the test-environment and click on "Launch". Search for MOLGENIS.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 77 KiB

View File

@ -0,0 +1,61 @@
categories:
- MOLGENIS
questions:
- variable: ingress.hosts[0].name
default: "test.molgenis.org"
description: "Hostname for your stack"
type: hostname
required: true
group: "Services and Load Balancing"
label: Hostname
- variable: molgenis.image.repository
default: "registry.hub.docker.com"
description: "Select a registry to pull from"
type: enum
options:
- "registry.hub.docker.com"
- "registry.molgenis.org"
required: true
group: "MOLGENIS - Version"
label: Registry
- variable: molgenis.image.tag
default: "stable"
description: "Select a MOLGENIS version (check the registry.molgenis.org or hub.docker.com for other tags)"
type: string
required: true
group: "MOLGENIS - Version"
label: Version
- variable: molgenis.resources.limits.cpu
default: 1
description: "CPU limit for this MOLGENIS instance"
type: enum
options:
- "1"
- "2"
- "3"
- "4"
required: true
group: "MOLGENIS - Resource limits"
label: CPU limit
- variable: molgenis.resources.limits.memory
default: 1250Mi
description: "Memory limit for this MOLGENIS instance"
type: enum
options:
- "1250Mi"
- "1500Mi"
- "2000Mi"
- "2500Mi"
required: true
group: "MOLGENIS - Resource limits"
label: Memory limit
- variable: molgenis.javaOpts
default: "-Xmx1g -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled"
description: "Java runtime options for the MOLGENIS instance"
type: enum
options:
- "-Xmx1g -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled"
- "-Xmx2g -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled"
group: "MOLGENIS - Resource limits"
label: Java memory options

View File

@ -0,0 +1,19 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "molgenis.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
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 "molgenis.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "molgenis.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "molgenis.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
{{- end }}

View File

@ -0,0 +1,32 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "molgenis.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "molgenis.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "molgenis.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

View File

@ -0,0 +1,124 @@
apiVersion: apps/v1beta2
kind: Deployment
metadata:
{{- with .Values.ingress.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
name: {{ template "molgenis.fullname" . }}
labels:
app: {{ template "molgenis.name" . }}
chart: {{ template "molgenis.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ template "molgenis.name" . }}
release: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ template "molgenis.name" . }}
release: {{ .Release.Name }}
spec:
containers:
- name: molgenis
{{- with .Values.molgenis }}
image: "{{ .image.repository }}/{{ .image.name }}:{{ .image.tag }}"
imagePullPolicy: {{ .image.pullPolicy }}
env:
- name: molgenis.home
value: /home/molgenis
- name: opencpu.uri.host
value: localhost
- name: elasticsearch.transport.addresses
value: localhost:9300
- name: elasticsearch.cluster.name
value: {{ $.Values.elasticsearch.clusterName }}
- name: db_uri
value: "jdbc:postgresql://localhost/{{ $.Values.postgres.db }}"
- name: db_user
value: {{ $.Values.postgres.user }}
- name: db_password
value: {{ $.Values.postgres.password }}
- name: admin.password
value: {{ .adminPassword }}
- name: CATALINA_OPTS
value: "{{ .javaOpts }}"
ports:
- containerPort: 8080
# livenessProbe:
# httpGet:
# path: /
# port: 8080
# readinessProbe:
# httpGet:
# path: /api/v2/version
# port: 8080
resources:
{{ toYaml .resources | indent 12 }}
{{- end }}
- name: elasticsearch
{{- with .Values.elasticsearch }}
image: "{{ .image.repository }}:{{ .image.tag }}"
imagePullPolicy: {{ .image.pullPolicy }}
env:
- name: cluster.name
value: {{ .clusterName }}
- name: bootstrap.memory_lock
value: "true"
- name: ES_JAVA_OPTS
value: "{{ .javaOpts }}"
- name: xpack.security.enabled
value: "false"
- name: discovery.type
value: single-node
ports:
- containerPort: 9200
- containerPort: 9300
resources:
{{ toYaml .resources | indent 12 }}
{{- end }}
- name: postgres
{{- with .Values.postgres }}
image: "{{ .image.repository }}:{{ .image.tag }}"
imagePullPolicy: {{ .image.pullPolicy }}
env:
- name: POSTGRES_USER
value: {{ .user }}
- name: POSTGRES_PASSWORD
value: {{ .password }}
- name: POSTGRES_DB
value: {{ .db }}
ports:
- containerPort: 5432
resources:
{{ toYaml .resources | indent 12 }}
{{- end }}
- name: opencpu
{{- with .Values.opencpu }}
image: "{{ .image.repository }}:{{ .image.tag }}"
imagePullPolicy: {{ .image.pullPolicy }}
ports:
- containerPort: 8004
resources:
{{ toYaml .resources | indent 12 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}

View File

@ -0,0 +1,38 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "molgenis.fullname" . -}}
{{- $ingressPath := .Values.ingress.path -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
app: {{ template "molgenis.name" . }}
chart: {{ template "molgenis.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
{{- with .Values.ingress.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .name }}
http:
paths:
- path: {{ $ingressPath }}
backend:
serviceName: {{ $fullName }}
servicePort: 8080
{{- end }}
{{- end }}

View File

@ -0,0 +1,17 @@
apiVersion: v1
kind: Service
metadata:
name: {{ template "molgenis.fullname" . }}
labels:
app: {{ template "molgenis.name" . }}
chart: {{ template "molgenis.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
- name: molgenis
port: {{ .Values.service.port }}
selector:
app: {{ template "molgenis.name" . }}
release: {{ .Release.Name }}

View File

@ -0,0 +1,82 @@
# Default values for molgenis.
replicaCount: 1
service:
type: LoadBalancer
port: 8080
ingress:
enabled: true
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "0"
path: /
hosts:
- name: test.molgenis.org
tls: []
molgenis:
image:
repository: registry.molgenis.org
name: molgenis/molgenis-app
tag: 7.0.0-SNAPSHOT
pullPolicy: Always
adminPassword: admin
javaOpts: "-Xmx1g -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled"
resources:
limits:
cpu: 1
memory: 1250Mi
requests:
cpu: 200m
memory: 1Gi
postgres:
image:
repository: postgres
tag: 9.6-alpine
pullPolicy: IfNotPresent
user: molgenis
password: molgenis
db: molgenis
resources:
limits:
cpu: 1
memory: 250Mi
requests:
cpu: 100m
memory: 250Mi
elasticsearch:
image:
repository: docker.elastic.co/elasticsearch/elasticsearch
tag: 5.5.3
pullPolicy: IfNotPresent
javaOpts: "-Xms512m -Xmx512m"
clusterName: molgenis
resources:
limits:
cpu: 1
memory: 1500Mi
requests:
cpu: 100m
memory: 1Gi
opencpu:
image:
repository: molgenis/opencpu
tag: latest
pullPolicy: Always
resources:
limits:
cpu: 1
memory: 512Mi
requests:
cpu: 100m
memory: 256Mi
nodeSelector: {}
tolerations: []
affinity: {}

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

View File

@ -0,0 +1,6 @@
apiVersion: v1
appVersion: "1.0"
description: MOLGENIS vault
name: molgenis-vault
version: 0.1.1
icon: https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm/raw/master/molgenis-vault/catalogIcon-molgenis-vault.svg

52
molgenis-vault/README.md Normal file
View File

@ -0,0 +1,52 @@
# MOLGENIS Vault helm chart
This chart creates a vault operator, but NO vault.
The vault operator defines a new custom resource named `vault` that you can use to create vaults.
After launching the operator, create the molgenis vault manually:
`kubectl create -f resources/vault.yaml`
That creates a new vault with two vault pods.
See https://github.com/coreos/vault-operator/blob/master/doc/user/vault.md
## Parameters
### Azure cloud credentials
Define credentials for backup to the Azure Blob Store.
See [etcd-operator documentation](https://github.com/coreos/etcd-operator/blob/master/doc/user/abs_backup.md).
| Parameter | Description | Default |
| --------------- | ----------------------------- | ------------------ |
| `abs.account` | name of storage account | `fdlkops` |
| `abs.accessKey` | access key of storage account | `xxxx` |
| `abs.cloud` | name of cloud environment | `AzurePublicCloud` |
### Backup job
Define the schedule of the backup job
| Parameter | Description | Default |
| -------------------- | ---------------------------- | ------------- |
| `backupJob.enable` | Enable backup cronjob | `true` |
| `backupJob.schedule` | cron schedule for the backup | `0 12 * * 1` |
### UI
Parameter | Description | Default
--------- | ----------- | -------
`ui.replicaCount` | desired number of Vault UI pod | `1`
`ui.image.repository` | Vault UI container image repository | `djenriquez/vault-ui`
`ui.image.tag` | Vault UI container image tag | `latest`
`ui.resources` | Vault UI pod resource requests & limits | `{}`
`ui.nodeSelector` | node labels for Vault UI pod assignment | `{}`
`ui.ingress.enabled` | If true, Vault UI Ingress will be created | `true`
`ui.ingress.annotations` | Vault UI Ingress annotations | `{}`
`ui.ingress.host` | Vault UI Ingress hostname | `vault.molgenis.org`
`ui.ingress.tls` | Vault UI Ingress TLS configuration (YAML) | `[]`
`ui.vault.url` | Vault UI default vault url | `https://vault.vault-operator:8200`
`ui.vault.auth` | Vault UI login method | `GITHUB`
`ui.service.name` | Vault UI service name | `vault-ui`
`ui.service.type` | type of ui service to create | `ClusterIP`
`ui.service.externalPort` | Vault UI service target port | `8000`
`ui.service.internalPort` | Vault UI container port | `8000`
`ui.service.nodePort` | Port to be used as the service NodePort (ignored if `server.service.type` is not `NodePort`) | `0`

View File

@ -0,0 +1,627 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Layer_1"
x="0px"
y="0px"
width="500px"
height="264px"
viewBox="0 0 500 264"
enable-background="new 0 0 500 264"
xml:space="preserve"
sodipodi:docname="catalogIcon-molgenis-vault.svg"
inkscape:version="0.92.2 5c3e80d, 2017-08-06"><metadata
id="metadata5805"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs5803"><filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter6667"
x="-0.064315152"
width="1.1286303"
y="-0.12104943"
height="1.2420989"><feGaussianBlur
inkscape:collect="always"
stdDeviation="13.265"
id="feGaussianBlur6669" /></filter></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1166"
inkscape:window-height="588"
id="namedview5801"
showgrid="false"
inkscape:zoom="1"
inkscape:cx="202.52842"
inkscape:cy="106.4469"
inkscape:window-x="61"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="Layer_1" /><rect
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter6667)"
id="rect6665"
width="495"
height="263"
x="1"
y="1" /><image
y="24.641571"
x="4.9419723"
id="image5824"
xlink:href="data:image/png;base64,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
"
style="image-rendering:optimizeQuality"
preserveAspectRatio="none"
height="216.15865"
width="217.16856" /><g
data-name="Layer 2"
id="Layer_2"
transform="matrix(2.4080868,0,0,2.15985,284.82342,10.2181)"><g
id="Logo"><path
id="path6529"
d="M 10.39,89.27 V 87.16 H 8.46 v 2.11 h -1 v -5.08 h 1 v 2.13 h 1.94 v -2.13 h 1 v 5.08 z m 4.61,0 H 14.22 L 14.15,89 a 2.15,2.15 0 0 1 -1.14,0.32 c -0.7,0 -1,-0.46 -1,-1.09 0,-0.63 0.34,-1 1.11,-1 H 14 V 86.85 C 14,86.44 13.88,86.3 13.27,86.3 a 5.55,5.55 0 0 0 -1.06,0.11 l -0.12,-0.7 a 5.18,5.18 0 0 1 1.31,-0.17 c 1.2,0 1.55,0.41 1.55,1.32 z m -1,-1.38 h -0.71 c -0.31,0 -0.4,0.08 -0.4,0.36 0,0.28 0.09,0.37 0.38,0.37 a 1.55,1.55 0 0 0 0.72,-0.19 z m 3,1.46 a 4.67,4.67 0 0 1 -1.32,-0.21 l 0.13,-0.7 a 4.44,4.44 0 0 0 1.14,0.16 c 0.42,0 0.49,-0.09 0.49,-0.37 0,-0.28 0,-0.34 -0.67,-0.48 -0.93,-0.22 -1,-0.44 -1,-1.15 0,-0.71 0.34,-1.06 1.43,-1.06 a 5.22,5.22 0 0 1 1.14,0.13 L 18.25,86.4 A 7,7 0 0 0 17.2,86.29 c -0.42,0 -0.49,0.09 -0.49,0.32 0,0.23 0,0.32 0.54,0.44 1.07,0.27 1.17,0.41 1.17,1.16 0,0.75 -0.26,1.14 -1.42,1.14 z m 4.38,-0.08 v -2.56 c 0,-0.2 -0.09,-0.29 -0.31,-0.29 a 2.72,2.72 0 0 0 -1,0.31 v 2.54 h -1 v -5.15 l 1,0.14 v 1.62 a 3.48,3.48 0 0 1 1.4,-0.35 c 0.63,0 0.86,0.43 0.86,1.08 v 2.66 z m 1.76,-4.18 v -0.9 h 1 v 0.9 z m 0,4.18 v -3.66 h 1 v 3.67 z m 1.72,-3.63 c 0,-0.92 0.56,-1.45 1.86,-1.45 a 6.14,6.14 0 0 1 1.42,0.17 l -0.11,0.82 A 8,8 0 0 0 26.75,85 c -0.68,0 -0.9,0.23 -0.9,0.76 v 1.93 c 0,0.53 0.22,0.76 0.9,0.76 A 8,8 0 0 0 28,88.36 l 0.11,0.82 a 6.14,6.14 0 0 1 -1.42,0.17 c -1.3,0 -1.86,-0.53 -1.86,-1.45 z m 5.39,3.71 c -1.31,0 -1.66,-0.69 -1.66,-1.44 V 87 c 0,-0.75 0.35,-1.44 1.66,-1.44 1.31,0 1.66,0.69 1.66,1.44 v 0.93 c 0,0.72 -0.35,1.42 -1.66,1.42 z m 0,-3 c -0.51,0 -0.71,0.22 -0.71,0.63 v 1 c 0,0.41 0.2,0.63 0.71,0.63 0.51,0 0.71,-0.22 0.71,-0.63 v -1 C 31,86.53 30.76,86.31 30.25,86.31 Z m 4.35,0.06 a 7.58,7.58 0 0 0 -1,0.53 v 2.36 h -1 v -3.69 h 0.81 l 0.06,0.41 a 4.35,4.35 0 0 1 1,-0.48 z m 3.82,1.68 a 1.13,1.13 0 0 1 -1.26,1.29 5.48,5.48 0 0 1 -1,-0.11 v 1.5 l -1,0.14 v -5.3 h 0.76 l 0.09,0.31 a 2.06,2.06 0 0 1 1.21,-0.38 c 0.77,0 1.18,0.44 1.18,1.27 z m -2.28,0.41 a 4.41,4.41 0 0 0 0.85,0.1 c 0.34,0 0.48,-0.16 0.48,-0.49 v -1.33 c 0,-0.3 -0.12,-0.47 -0.47,-0.47 a 1.38,1.38 0 0 0 -0.85,0.33 z"
inkscape:connector-curvature="0" /><path
id="path6531"
d="m 21.73,93.36 h 4.12 l -6.26,21 h -5.86 l -6.26,-21 h 4.12 l 5.07,17.47 z"
inkscape:connector-curvature="0" /><path
id="path6533"
d="m 37.31,114.32 h -3.15 l -0.28,-1 a 8.38,8.38 0 0 1 -4.56,1.35 c -2.8,0 -4,-1.92 -4,-4.56 0,-3.12 1.35,-4.31 4.47,-4.31 h 3.68 v -1.61 c 0,-1.7 -0.47,-2.3 -2.93,-2.3 a 21.42,21.42 0 0 0 -4.25,0.47 l -0.47,-2.93 a 20,20 0 0 1 5.26,-0.72 c 4.82,0 6.23,1.7 6.23,5.54 z m -3.84,-5.79 h -2.84 c -1.26,0 -1.61,0.35 -1.61,1.51 0,1.16 0.35,1.54 1.54,1.54 a 6,6 0 0 0 2.9,-0.79 z"
inkscape:connector-curvature="0" /><path
id="path6535"
d="m 43.35,99 v 10.7 c 0,0.82 0.35,1.23 1.23,1.23 a 10.59,10.59 0 0 0 4,-1.29 V 99 h 3.84 v 15.33 H 49.49 L 49.11,113 A 15.35,15.35 0 0 1 43,114.64 c -2.55,0 -3.46,-1.79 -3.46,-4.53 V 99 Z"
inkscape:connector-curvature="0" /><path
id="path6537"
d="M 54.46,114.32 V 92.73 L 58.3,92.2 v 22.13 z"
inkscape:connector-curvature="0" /><path
id="path6539"
d="m 69.76,114 a 10.64,10.64 0 0 1 -3.37,0.6 c -2.8,0 -4.22,-1.32 -4.22,-4.06 V 102 h -2.3 v -3 h 2.3 V 95.19 L 66,94.65 V 99 h 3.93 l -0.24,3 H 66 v 8 a 1.21,1.21 0 0 0 1.38,1.35 7.39,7.39 0 0 0 1.92,-0.31 z"
inkscape:connector-curvature="0" /><path
id="path6541"
d="M 0,0 38.57,77.41 77.41,0 Z m 43.16,15.54 h 4.49 V 20 h -4.49 z m -8.94,18 H 29.73 V 29 h 4.49 z m 0,-6.73 h -4.49 v -4.54 h 4.49 z m 0,-6.73 h -4.49 v -4.54 h 4.49 z M 41,40.22 H 36.46 V 35.73 H 41 Z m 0,-6.73 H 36.46 V 29 H 41 Z m 0,-6.73 H 36.46 V 22.27 H 41 Z M 41,20 H 36.46 V 15.54 H 41 Z m 2.21,2.24 h 4.49 v 4.49 h -4.54 z m 0,11.22 V 29 h 4.49 v 4.49 z"
inkscape:connector-curvature="0" /></g></g><image
y="97.389206"
x="218.78775"
id="image6642"
xlink:href="data:image/png;base64,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
4T/s/9jRZNxUeVT76LJj1GPFxwaOFx7vaxY395zIPPG4ZUrL3ZPjT147Ne5U2+mI0+fOhJ45eTbg
7PFzPueaznudP3LB40L9RbeLda2urYcvuV463ObWVnfZ/XJDu2d7Y8eYjmNX/K6cuBp89cw19rWL
16Ovd9xIvHHr5sSbnbd4t57fzrn9+k7Bnf678+4R7pXeV79f8UD/QdW/rP+1r9Ot8+jD4Ietj+If
3X3MffzyifTJ567ip/SnFc+MntU8d3re1B3a3f5iwouul+KX/T0lf2r8ueGV1atDf/n/1do7vrfr
teT1wJslb3Xf7vjb5e+Wvti+B+9y3/W/L/2g+2HnR4+PZz8lf3rWP+0z6fPaL9ZfGr9GfL03kDsw
IOZIOIqjAAYbmpEBwJsdANBT4NmhHQDqBOXdTCGI8j6pIPCfWHl/U4gbADv8AUicB0AkPKNsgs0c
Mg2+5UfwBH+AOjsPt0GRZjg7KX3R4I2F8GFg4K0BAKRGAL5IBgb6Nw4MfKmGwd4GoDlPeSeUi/wO
ukVxzrlkOrsY/CD/Bs85cE/8nz0/AAAACXBIWXMAABYlAAAWJQFJUiTwAAABnWlUWHRYTUw6Y29t
LmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0
az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMu
b3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJk
ZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4
aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWERpbWVuc2lvbj4xMjY8L2V4aWY6UGl4ZWxY
RGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+MTQyPC9leGlmOlBpeGVs
WURpbWVuc2lvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94Onht
cG1ldGE+Cn6ipB4AAAAcaURPVAAAAAIAAAAAAAAARwAAACgAAABHAAAARwAACnXMeSkEAAAKQUlE
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
4lGQiK+t1DFPvBPeLKbiyNhmMRlPAiJpZ13aQ2ch/8lSW1v2ogiVzI4FZsdptrJ/1pmOPeyg2IN/
eWXLFd8s0T6+WaJ9PAS7w7Qn4j0yGW6ZeJYlAz0jwVQMZ1MMc5aR0SHMeujn7A0lmFe8JwiJxTqs
ix7sCG3lXtmOYzsF67vf6Mce4ur2wkdMJuK/34hiZ/BAEmgCDzH/euK9smKYwHqg82Iq1DOadioa
zLpuF4RSOWAnmMqLVWrRftYP7YDYh/34h//sTN5Of0i2XPEYhAExnIivvfoftcSTUVQMGRrKYCrK
+9lCCUQI+3z0ecKRYF4JvhMwjsTFD/RgR2hr90oveqajz+Pi2P10f+AjJluueBQQMIhwg2OYACfi
PyukoUT45cRDOBVDZZGBMczZy3ywz4/1Mx57ikrWKWq3EwLGL/cjhrGH+b4e/diLzOt/4YpHAQ6g
2A0KYRxiPtjHx/oZjz1FJevE/MBOtwtiODLAofE+3zH2MN/Xox97kXn9b5n4vIrSuGpFIBFfLT5K
syYRX1qoq6UoEV8tPkqzJhFfWqirpSgRXy0+SrMmEV9aqKulKBFfLT5KsyYRX1qoq6UoEV8tPkqz
JhFfWqirpSgRXy0+SrMmEV9aqKulKBFfLT5KsyYRX1qoq6UoEV8tPkqzJhFfWqirpSgRXy0+SrMm
EV9aqKulKBFfLT5KsyYRX1qoq6UoEV8tPkqzJhFfWqirpSgRXy0+SrPmL/hk6fsEzapeAAAAAElF
TkSuQmCC
"
style="image-rendering:optimizeQuality"
preserveAspectRatio="none"
height="94.666664"
width="84" /><g
inkscape:groupmode="layer"
id="layer1"
inkscape:label="base"
style="opacity:1" /></svg>

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,9 @@
dependencies:
- name: vault-operator
repository: https://kubernetes-charts.storage.googleapis.com/
version: 0.1.1
- name: etcd-operator
repository: https://kubernetes-charts.storage.googleapis.com/
version: 0.8.0
digest: sha256:47aa645df7dfce9760905800321599de05995ae50090735d45310936dbaa46de
generated: 2018-09-06T18:59:39.861922543+02:00

View File

@ -0,0 +1,7 @@
dependencies:
- name: vault-operator
version: ^0.1.1
repository: https://kubernetes-charts.storage.googleapis.com/
- name: etcd-operator
version: ^0.8.0
repository: https://kubernetes-charts.storage.googleapis.com/

View File

@ -0,0 +1,15 @@
# Use kubectl create -f restore.yaml to manually execute a restore of the vault
apiVersion: "etcd.database.coreos.com/v1beta2"
kind: "EtcdRestore"
metadata:
# The restore CR name must be the same as spec.etcdCluster.name
name: vault-etcd
namespace: vault-operator
spec:
etcdCluster:
# The namespace is the same as this EtcdRestore CR
name: vault-etcd
backupStorageType: ABS
abs:
path: vault/backup-<specify the backup name>
absSecret: abs

View File

@ -0,0 +1,9 @@
# Use kubectl create -f vault.yaml to manually create a vault
apiVersion: "vault.security.coreos.com/v1alpha1"
kind: "VaultService"
metadata:
name: "vault"
namespace: "vault-operator"
spec:
nodes: 2
version: "0.9.1-0"

View File

@ -0,0 +1,13 @@
Vault operator created
Next steps:
* Manually create a vault using resources/vault.yaml
* Manually restore a backup using resources/backup.yaml
* Unseal the vault pods
{{ if .Values.backupJob.enable }}
!! Make sure to check if the backups succeed !!
{{ else }}
!!!!!! NO BACKUPS CONFIGURED !!!!!!
{{ end }}

View File

@ -0,0 +1,54 @@
{{/*
Define vault ui fullname
*/}}
{{- define "vault.ui.fullname" -}}
{{- printf "%s-ui" .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Define vault service url for the ui
*/}}
{{- define "vault.service.url" -}}
{{- printf "https://%s:8200" .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/* See https://github.com/helm/helm/issues/4535 */}}
{{- define "call-nested" }}
{{- $dot := index . 0 }}
{{- $subchart := index . 1 }}
{{- $template := index . 2 }}
{{- include $template (dict "Chart" (dict "Name" $subchart) "Values" (index $dot.Values $subchart) "Release" $dot.Release "Capabilities" $dot.Capabilities) }}
{{- end }}
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "molgenis-vault.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "molgenis-vault.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "molgenis-vault.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

View File

@ -0,0 +1,10 @@
# Secret to access microsoft azure blob store
apiVersion: v1
kind: Secret
metadata:
name: abs
type: Opaque
stringData:
storage-account: {{ .Values.abs.account }}
storage-key: {{ .Values.abs.accessKey }}
cloud: {{ .Values.abs.cloud }}

View File

@ -0,0 +1,18 @@
# configmap to use as a template by the backup cronjob to create etcdbackup instances
apiVersion: v1
kind: ConfigMap
metadata:
name: backup-config
data:
backup_cr.yaml: |
apiVersion: "etcd.database.coreos.com/v1beta2"
kind: "EtcdBackup"
metadata:
generateName: vault-backup-
spec:
etcdEndpoints: ["https://vault-etcd-client:2379"]
storageType: ABS
clientTLSSecret: vault-etcd-client-tls
abs:
path: vault/backup.<NOW>
absSecret: abs

View File

@ -0,0 +1,30 @@
{{- if .Values.backupJob.enable }}
# cronjob that creates etcdbackups using the etcd backup serviceaccount
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: etcd-backup
spec:
schedule: {{ .Values.backupJob.schedule | quote }}
jobTemplate:
spec:
template:
spec:
serviceAccountName: {{ include "call-nested" (list . "etcd-operator" "etcd-operator.serviceAccountName") }}
containers:
- name: etcd-backup
image: lachlanevenson/k8s-kubectl
command:
- /bin/sh
- "-ec"
- |
sed -e "s|<NOW>|$(date '+%Y-%m-%d_%H:%M:%S')|g" /var/etcd_backup/backup_cr.yaml | kubectl create -f -
volumeMounts:
- name: backup-config
mountPath: /var/etcd_backup
restartPolicy: OnFailure
volumes:
- name: backup-config
configMap:
name: backup-config
{{- end }}

View File

@ -0,0 +1,30 @@
{{- if .Values.ui.ingress.enabled -}}
{{- $serviceName := include "vault.ui.fullname" . -}}
{{- $servicePort := .Values.ui.service.externalPort -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ template "vault.ui.fullname" . }}
labels:
app: {{ template "molgenis-vault.name" . }}
chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
{{- range $key, $value := .Values.ui.ingress.annotations }}
{{ $key }}: {{ $value | quote }}
{{- end }}
spec:
rules:
- host: {{ .Values.ui.ingress.host }}
http:
paths:
- path:
backend:
serviceName: {{ $serviceName }}
servicePort: {{ $servicePort }}
{{- if .Values.ui.ingress.tls }}
tls:
{{ toYaml .Values.ui.ingress.tls | indent 4 }}
{{- end -}}
{{- end -}}

View File

@ -0,0 +1,23 @@
apiVersion: v1
kind: Service
metadata:
name: {{ template "vault.ui.fullname" . }}
labels:
app: {{ template "vault-operator.name" . }}
chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
type: {{ .Values.ui.service.type }}
ports:
- port: {{ .Values.ui.service.externalPort }}
targetPort: {{ .Values.ui.service.internalPort }}
protocol: TCP
name: {{ .Values.ui.service.name }}
{{- if .Values.ui.service.nodePort }}
nodePort: {{ .Values.ui.service.nodePort }}
{{- end }}
selector:
app: {{ template "vault-operator.name" . }}
release: {{ .Release.Name }}
component: {{ .Values.ui.name }}

View File

@ -0,0 +1,50 @@
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: {{ template "vault.ui.fullname" . }}
labels:
app: {{ template "vault-operator.name" . }}
chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
component: {{ .Values.ui.name }}
spec:
replicas: {{ .Values.ui.replicaCount }}
template:
metadata:
labels:
app: {{ template "vault-operator.name" . }}
release: {{ .Release.Name }}
component: {{ .Values.ui.name }}
spec:
containers:
- name: {{ .Values.ui.name }}
image: "{{ .Values.ui.image.repository }}:{{ .Values.ui.image.tag }}"
imagePullPolicy: {{ .Values.imagePullPolicy }}
env:
- name: VAULT_URL_DEFAULT
{{- if .Values.ui.vault.url }}
value: {{ .Values.ui.vault.url }}
{{ else }}
value: {{ template "vault.service.url" . }}
{{- end }}
- name: VAULT_AUTH_DEFAULT
value: {{ .Values.ui.vault.auth }}
- name: NODE_TLS_REJECT_UNAUTHORIZED
value: '0'
ports:
- containerPort: {{ .Values.ui.service.internalPort }}
livenessProbe:
httpGet:
path: /
port: {{ .Values.ui.service.internalPort }}
readinessProbe:
httpGet:
path: /
port: {{ .Values.ui.service.internalPort }}
resources:
{{ toYaml .Values.ui.resources | indent 12 }}
{{- if .Values.ui.nodeSelector }}
nodeSelector:
{{ toYaml .Values.ui.nodeSelector | indent 8 }}
{{- end }}

View File

@ -0,0 +1,79 @@
# Default values for molgenis-vault.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# abs gives details of the credentials to reach the azure backup storage
abs:
# account is the name of the Storage account
account: fdlkops
# access key for the Storage account
accessKey: xxxx
# default cloud
cloud: AzurePublicCloud
# backupjob describes the backup cronjob
backupJob:
# enable enables the backup job
enable: true
# schedule gives the cron schedule for the backup job
schedule: "0 12 * * 1"
###
# All of the config variables related to setting up the etcd-operator
# If you want more information about the variables exposed, please visit:
# https://github.com/kubernetes/charts/tree/master/stable/etcd-operator#configuration
###
etcd-operator:
deployments:
etcdOperator: true
backupOperator: true
restoreOperator: true
serviceAccount:
etcdOperatorServiceAccount:
create: true
backupOperatorServiceAccount:
create: true
restoreOperatorServiceAccount:
create: true
etcdOperator:
image:
tag: v0.9.2
backupOperator:
image:
tag: v0.9.2
restoreOperator:
image:
tag: v0.9.2
ui:
name: "vault-ui"
replicaCount: 1
image:
repository: djenriquez/vault-ui
tag: latest
service:
name: vault-ui
type: ClusterIP
externalPort: 8000
internalPort: 8000
# nodePort: 32001
ingress:
enabled: true
# Used to create Ingress record (should used with service.type: ClusterIP).
host: vault.molgenis.org
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
#requests:
# cpu: 100m
# memory: 128Mi
nodeSelector: {}
vault:
auth: GITHUB
url: https://vault.vault-operator:8200

8
molgenis/Chart.yaml Normal file
View File

@ -0,0 +1,8 @@
apiVersion: v1
appVersion: "1.0"
description: MOLGENIS - helm stack (in BETA)
name: molgenis-beta
version: 0.3.0
sources:
- https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm.git
icon: https://git.webhosting.rug.nl/molgenis/molgenis-ops-docker-helm/raw/master/molgenis/catalogIcon-molgenis.svg

122
molgenis/README.md Normal file
View File

@ -0,0 +1,122 @@
# MOLGENIS
This chart is used for acceptance and production use cases.
## Containers
This chart spins up a MOLGENIS instance with HTTPD. The created containers are:
- MOLGENIS
## Provisioning
You can choose from which registry you want to pull. There are 2 registries:
- https://registry.molgenis.org
- https://hub.docker.com
The registry.molgenis.org contains the bleeding edge versions (PR's and master merges). The hub.docker.com contains the released artifacts (MOLGENIS releases and release candidates).
The three properties you need to specify are:
- ```molgenis.image.repository```
- ```molgenis.image.name```
- ```molgenis.image.tag```
Besides determining which image you want to pull, you also have to set an administrator password. You can do this by specifying the following property.
- ```molgenis.adminPassword```
## Services
When you start MOLGENIS you need:
- an elasticsearch instance (5.5.6)
- an postgres instance (9.6)
You can attach additional services like:
- an opencpu instance
### Elasticsearch
You can configure elasticsearch by giving in the cluster location.
To configure the transport address you can address the node communication channel but also the native JAVA API. Which MOLGENIS uses to communicate with Elasticsearch.
From Elasticsearch version 6 and further the JAVA API is not supported anymore. At this moment you can only use Elastic instance till major version 5.
- ```molgenis.services.elasticsearch.transportAddresses: localhost:9300```
To configure the index on a Elasticsearch cluster you can specify the clusterName property.
- ```molgenis.services.elasticsearch.clusterName: molgenis```
### Postgres
You can specify the location of the postgres instance by specify the following property:
- ```molgenis.services.postgres.host: localhost```
You can specify the schema by filling out this property:
- ```molgenis.services.postgres.scheme: molgenis```
You can specify credentials for the database scheme by specifying the following properties:
- ```molgenis.services.postgres.user: molgenis```
- ```molgenis.services.postgres.password: molgenis```
To test you can use the **PostgreSQL**-helm chart of Kubernetes and specify these answers:
```bash
# answers for postgresql chart
postgresUser=molgenis
postgresPassword=molgenis
postgresDatabase=molgenis
persistence.enabled=false
```
### OpenCPU
You can specify the location of the OpenCPU cluster by specifying this property:
- ```molgenis.services.opencpu.host: localhost```
You can test OpenCPU settings using the **OpenCPU**-helm chart of MOLGENIS.
## Resources
You can specify resources by resource type. There are 2 resource types.
- memory of container
- maximum heap space JVM
Specify memory usage of container:
- ```molgenis.resources.limits.memory```
Specify memory usage for Java JVM:
- ```molgenis.javaOpts.maxHeapSpace```
Select the resources you need dependant on the customer you need to serve.
## Persistence
You can enable persistence on your MOLGENIS stack by specifying the following property.
- ```persistence.enabled```
You can also choose to retain the volume of the NFS.
- ```persistence.retain```
The size and claim name can be specified per service. There are now two services that can be persist.
- MOLGENIS
- ElasticSearch
MOLGENIS persistent properties.
- ```molgenis.persistence.claim```
- ```molgenis.persistence.size```
ElasticSearch persistent properties.
- ```elasticsearch.persistence.claim```
- ```elasticsearch.persistence.size```
### Resolve you persistent volume
You do not know which volume is attached to your MOLGENIS instance. You can resolve this by executing:
```
kubectl get pv
```
You can now view the persistent volume claims and the attached volumes.
| NAME | CAPACITY | ACCESS | MODES | RECLAIM | POLICY | STATUS | CLAIM | STORAGECLASS | REASON | AGE |
| ---- | -------- | ------ | ----- | ------- | ------ | ------ | ----- | ------------ | ------ | --- |
| pvc-45988f55-900f-11e8-a0b4-005056a51744 | 30G | RWX | | Retain | Bound | molgenis-solverd/molgenis-nfs-claim | nfs-provisioner-retain | | | 33d |
| pvc-3984723d-220f-14e8-a98a-skjhf88823kk | 30G | RWO | | Delete | Bound | molgenis-test/molgenis-nfs-claim | nfs-provisioner | | | 33d |
You see the ```molgenis-test/molgenis-nfs-claim``` is bound to the volume: ```pvc-3984723d-220f-14e8-a98a-skjhf88823kk```.
When you want to view the data in the this volume you can go to the nfs-provisioning pod and execute the shell. Go to the directory ```export``` and lookup the directory ```pvc-3984723d-220f-14e8-a98a-skjhf88823kk```.
## Firewall
Is defined at cluster level. This chart does not facilitate firewall configuration.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 77 KiB

131
molgenis/questions.yml Normal file
View File

@ -0,0 +1,131 @@
categories:
- MOLGENIS
questions:
- variable: ingress.hosts[0].name
label: Hostname
default: "test.molgenis.org"
description: "Hostname for your stack"
type: hostname
required: true
group: "Load Balancing"
- variable: molgenis.image.repository
label: Registry
default: "registry.hub.docker.com"
description: "Select a registry to pull from"
type: enum
options:
- "registry.hub.docker.com"
- "registry.molgenis.org"
required: true
group: "Provisioning"
- variable: molgenis.image.tag
label: Version
default: ""
description: "Select a MOLGENIS version (check the registry.molgenis.org or hub.docker.com for released tags)"
type: string
required: true
group: "Provisioning"
- variable: molgenis.adminPassword
label: Administrator password
default: ""
description: "Enter an administrator password"
type: password
required: true
group: "Provisioning"
- variable: molgenis.services.opencpu.host
label: OpenCPU cluster
default: "localhost"
description: "Specify the OpenCPU cluster"
type: string
required: true
group: "Services"
- variable: molgenis.services.postgres.host
label: Postgres cluster location
default: "postgresql.molgenis-postgresql.svc"
description: "Set the location of the postgres cluster"
type: string
required: true
group: "Services"
- variable: molgenis.services.postgres.scheme
label: Database scheme
default: "molgenis"
description: "Set the database scheme"
type: string
required: true
group: "Services"
- variable: molgenis.services.postgres.user
label: Database username
default: "molgenis"
description: "Set user of the database scheme"
type: string
required: true
group: "Services"
- variable: molgenis.services.postgres.password
label: Database password
default: "molgenis"
description: "Set the password of the database scheme"
type: string
required: true
group: "Services"
- variable: molgenis.resources.limits.memory
label: Container memory limit
default: 1250Mi
description: "Memory limit for this MOLGENIS container"
type: enum
options:
- "1250Mi"
- "2500Mi"
required: true
group: "Resources"
- variable: molgenis.resources.requests.memory
label: Container memory reservation
default: 1250Mi
description: "Memory reservation for this MOLGENIS container (must fit in the selected memory limit for the container)"
type: enum
options:
- "1250Mi"
- "2500Mi"
required: true
group: "Resources"
- variable: molgenis.javaOpts.maxHeapSpace
label: Maximum heap space (JVM)
default: "1g"
description: "Maximum heap space MOLGENIS container JVM. Please not this should fit in your container memory limit"
type: enum
options:
- "1g"
- "2g"
group: "Resources"
- variable: persistence.enabled
default: false
description: "Do you want to use persistence"
type: boolean
required: true
group: "Persistence"
label: Persistence
show_subquestion_if: true
subquestions:
- variable: persistence.retain
default: false
description: "Do you want to retain the persistent volume"
type: boolean
label: Retain volume
- variable: molgenis.persistence.size
default: "30Gi"
description: "Size of MOLGENIS filestore (PostgreSQL and ElasticSearch excluded)"
type: enum
options:
- "30Gi"
- "50Gi"
- "100Gi"
label: Size MOLGENIS filestore
- variable: elasticsearch.persistence.size
default: "50Gi"
description: "Size of ElasticSearch data (directory that is persist: /usr/share/elasticsearch/data)"
type: enum
options:
- "50Gi"
- "100Gi"
- "200Gi"
label: Size for ElasticSearch data

View File

@ -0,0 +1,19 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "molgenis.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
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 "molgenis.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "molgenis.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "molgenis.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:80
{{- end }}

View File

@ -0,0 +1,32 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "molgenis.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "molgenis.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "molgenis.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

View File

@ -0,0 +1,126 @@
apiVersion: apps/v1beta2
kind: Deployment
metadata:
{{- with .Values.ingress.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
name: {{ template "molgenis.fullname" . }}
labels:
app: {{ template "molgenis.name" . }}
chart: {{ template "molgenis.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ template "molgenis.name" . }}
release: {{ .Release.Name }}
template:
metadata:
labels:
app: {{ template "molgenis.name" . }}
release: {{ .Release.Name }}
spec:
containers:
- name: molgenis
{{- with .Values.molgenis }}
image: {{ .image.repository }}/{{ .image.name }}:{{ .image.tag }}
imagePullPolicy: {{ .image.pullPolicy }}
env:
- name: molgenis.home
value: /home/molgenis
- name: opencpu.uri.host
value: {{ .services.opencpu.host }}
- name: elasticsearch.transport.addresses
value: {{ .services.elasticsearch.transportAddresses }}
- name: elasticsearch.cluster.name
value: {{ .services.elasticsearch.clusterName }}
- name: db_uri
value: jdbc:postgresql://{{ .services.postgres.host }}/{{ .services.postgres.scheme }}
- name: db_user
value: {{ .services.postgres.user }}
- name: db_password
value: {{ .services.postgres.password }}
- name: admin.password
value: {{ .adminPassword }}
- name: CATALINA_OPTS
value: "-Xmx{{ .javaOpts.maxHeapSpace }} -XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled"
ports:
- containerPort: 8080
{{- if $.Values.persistence.enabled }}
volumeMounts:
- name: molgenis-nfs
mountPath: /home/molgenis
{{- end }}
livenessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 60
periodSeconds: 5
failureThreshold: 25
successThreshold: 1
readinessProbe:
httpGet:
path: /api/v2/version
port: 8080
initialDelaySeconds: 120
periodSeconds: 30
failureThreshold: 3
successThreshold: 1
resources:
{{ toYaml .resources | indent 12 }}
{{- end }}
- name: elasticsearch
{{- with .Values.elasticsearch }}
image: "{{ .image.repository }}:{{ .image.tag }}"
imagePullPolicy: {{ .image.pullPolicy }}
env:
- name: cluster.name
value: {{ .clusterName }}
- name: bootstrap.memory_lock
value: "true"
- name: ES_JAVA_OPTS
value: "{{ .javaOpts }}"
- name: xpack.security.enabled
value: "false"
- name: discovery.type
value: single-node
ports:
- containerPort: 9200
- containerPort: 9300
{{- if $.Values.persistence.enabled }}
volumeMounts:
- name: elasticsearch-nfs
mountPath: /usr/share/elasticsearch/data
{{- end }}
resources:
{{ toYaml .resources | indent 12 }}
{{- end }}
{{- if .Values.persistence.enabled }}
volumes:
- name: molgenis-nfs
persistentVolumeClaim:
claimName: {{ .Values.molgenis.persistence.claim }}
- name: elasticsearch-nfs
persistentVolumeClaim:
claimName: {{ .Values.elasticsearch.persistence.claim }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}

View File

@ -0,0 +1,38 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "molgenis.fullname" . -}}
{{- $ingressPath := .Values.ingress.path -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
app: {{ template "molgenis.name" . }}
chart: {{ template "molgenis.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
{{- with .Values.ingress.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .name }}
http:
paths:
- path: {{ $ingressPath }}
backend:
serviceName: {{ $fullName }}
servicePort: 8080
{{- end }}
{{- end }}

View File

@ -0,0 +1,19 @@
{{- if .Values.persistence.enabled -}}
apiVersion: extensions/v1beta1
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: {{ .Values.elasticsearch.persistence.claim }}
annotations:
{{- if .Values.persistence.retain }}
volume.beta.kubernetes.io/storage-class: "nfs-provisioner-retain"
{{- else }}
volume.beta.kubernetes.io/storage-class: "nfs-provisioner"
{{- end }}
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: {{ .Values.elasticsearch.persistence.size }}
{{- end }}

View File

@ -0,0 +1,19 @@
{{- if .Values.persistence.enabled -}}
apiVersion: extensions/v1beta1
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: {{ .Values.molgenis.persistence.claim }}
annotations:
{{- if .Values.persistence.retain }}
volume.beta.kubernetes.io/storage-class: "nfs-provisioner-retain"
{{- else }}
volume.beta.kubernetes.io/storage-class: "nfs-provisioner"
{{- end }}
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: {{ .Values.molgenis.persistence.size }}
{{- end }}

View File

@ -0,0 +1,17 @@
apiVersion: v1
kind: Service
metadata:
name: {{ template "molgenis.fullname" . }}
labels:
app: {{ template "molgenis.name" . }}
chart: {{ template "molgenis.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
type: {{ .Values.service.type }}
ports:
- name: molgenis
port: {{ .Values.service.port }}
selector:
app: {{ template "molgenis.name" . }}
release: {{ .Release.Name }}

77
molgenis/values.yaml Normal file
View File

@ -0,0 +1,77 @@
# Default values for molgenis.
replicaCount: 1
service:
type: LoadBalancer
port: 8080
ingress:
enabled: true
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "0"
path: /
hosts:
- name: test.molgenis.org
tls: []
molgenis:
image:
repository: registry.hub.docker.com
name: molgenis/molgenis-app
tag: stable
pullPolicy: Always
adminPassword:
javaOpts:
maxHeapSpace: "1g"
resources:
limits:
cpu: 1
memory: 1250Mi
requests:
cpu: 200m
memory: 1250Mi
persistence:
claim: molgenis-nfs-claim
size: 30Gi
services:
opencpu:
host: localhost
elasticsearch:
transportAddresses: localhost:9300
clusterName: molgenis
postgres:
host: localhost
scheme: molgenis
user: molgenis
password: molgenis
elasticsearch:
image:
repository: docker.elastic.co/elasticsearch/elasticsearch
tag: 5.5.3
pullPolicy: IfNotPresent
javaOpts: "-Xms1g -Xmx1g"
clusterName: molgenis
resources:
limits:
cpu: 2
memory: 3Gi
requests:
cpu: 100m
memory: 1Gi
persistence:
claim: elasticsearch-nfs-claim
size: 50Gi
persistence:
enabled: false
retain: false
nodeSelector: {
deployPod: "true"
}
tolerations: []
affinity: {}

View File

@ -1,6 +0,0 @@
apiVersion: v1
appVersion: "1.0"
description: Nexus stack for MOLGENIS
name: nexus
version: 0.1.2
icon: https://github.com/sidohaakma/molgenis-docker-helm/blob/master/nexus/catalogIcon-molgenis-nexus.svg

View File

@ -1,16 +0,0 @@
apiVersion: v1
kind: PersistentVolume
metadata:
name: molgenis-nexus-data
labels:
name: nfs2
spec:
storageClassName: nfs-class
capacity:
storage: 50Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
server: 192.168.64.12
path: /gcc/molgenis/nexus

View File

@ -1,11 +0,0 @@
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: molgenis-nexus-data
spec:
storageClassName: nfs-class
accessModes:
- ReadWriteMany
resources:
requests:
storage: 50Gi