├── .gitignore ├── LICENSE ├── Makefile ├── README.md └── scripts ├── cicd-tools ├── add-gitlab.sh ├── add-helm.sh ├── add-jenkins.sh ├── add-local-storage.sh ├── add-nexus.sh ├── add-spinnaker.sh ├── common-cicd.sh ├── configs │ └── README.md ├── del-local-storage.sh ├── download-snaps.sh ├── expose-dashboard.sh ├── install-k8s-base.sh ├── install-microk8s.sh └── templates │ ├── persistent_volume.yaml │ ├── pv_claim.yaml │ ├── storage_class.yaml │ └── test-pod.yaml └── mp ├── cloud.init ├── common.sh ├── create-single-vm.sh ├── destroy-single-vm.sh └── ssh-single-vm.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # The configs directory is for realized (auto-generated) yamls. Ignore *.yaml's in there. 2 | scripts/cicd-tools/configs/ 3 | # snaps/ holds cached snaps .. don't check in .. use download-snaps.sh to populate. 4 | scripts/cicd-tools/snaps/ 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/canonical-labs/cicd-microk8s-basic/a3500c8804ff70dd68f85dd82bbe84d3305b08dc/Makefile -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Local CICD Pipelines on Ubuntu Kubernetes 2 | 3 | ## Introduction 4 | 5 | The advent of Kubernetes has benefitted CI/CD initiatives greatly - it gives the tools and components commonly used in CI/CD a known set of APIs to work with. These Kubernetes APIs can be used for their own deployment, as well as leveraged as part of your service or application. 6 | 7 | The reference examples in this repository will focus on a couple of deployment models: 8 | 9 | 1. Deploy everything in a single server 10 | 2. Deploy everything in a distributed set of servers (_not yet started_) 11 | 3. For both of the above we will start simply, using one or more VMs. The benefit is this approach is that many heterogenous environments provide the ability to launch VMs - from laptop to private clouds to public clouds. 12 | 13 | We'll describe the initial set of components that the examples deploy, along with a list of the complete set of components available in this repo. 14 | 15 | # All-in-One 16 | 17 | For this reference example, we'll deploy the entire set of components onto a single kubernetes cluster, and use that cluster as our dev cluster for deploying a hello-world application. This is useful for testing the initial capabilities of an application - from deployment / configuration-as-code mechanisms to functional / acceptance tests against the application. 18 | 19 | ## Setup Instructions 20 | 21 | The example leverages several scripts. The variables in the scripts can be overwritten without changing the scripts themselves. We'll start with a summary of the instructions to follow to setup the software. Then the next section describes the variables in more detail. 22 | 23 | ### Installation Summary 24 | 25 | Here's a summary of the steps. More detail will come in following sections. The emphasis here is on the bare minimum set of steps. 26 | 27 | ``` 28 | #-- HOST --# 29 | git clone https://github.com/canonical-labs/cicd-microk8s-basic.git cicd 30 | cd cicd 31 | cicd/scripts/mp/create-single-vm.sh 32 | cicd/scripts/mp/ssh-single-vm.sh 33 | 34 | #-- VM --# 35 | sudo /canonical/labs/cicd/scripts/install-microk8s.sh 36 | /canonical/labs/cicd/scripts/add-local-storage.sh 37 | /canonical/labs/cicd/scripts/add-helm.sh 38 | /canonical/labs/cicd/scripts/add-gitlab.sh 39 | /canonical/labs/cicd/scripts/add-jenkins.sh 40 | (tbd) /canonical/labs/cicd/scripts/add-nexus.sh 41 | (tbd) /canonical/labs/cicd/scripts/add-spinnaker.sh 42 | 43 | #-- OPTIONAL --# 44 | # if you plan on doing install-all a lot - strongly advise downloading snaps 45 | # Do this before install-microk8s.sh to get the full benefit. 46 | ./download-snaps.sh 47 | 48 | ``` 49 | 50 | 51 | ### Key variables 52 | 53 | **Please note**: *it's possible that the values in these tables drift from what is in the source files. Please review source files to confirm defaults* 54 | 55 | | Variable | Default | Description | File | 56 | |---|---|---|---| 57 | | VM_IMAGE | bionic | The version of Ubuntu to use. "bionic" is Ubuntu 18.04 | scripts/mp/common.sh | 58 | | SINGLE_VM_NAME | cicd-single | The name of the vm for multipass. ```multipass list``` will show the status of this VM. | scripts/mp/common.sh | 59 | | HOME | Defined by ENV, or "temp" | Your home directory. Used by MOUNT_SRC. Most linux systems define the HOME environment variable. | scripts/mp/common.sh | 60 | | MOUNT_SRC | $HOME/.canonical/labs/cicd | The location on the host of the directory to use inside the VM. All assets (e.g. container registry) will be stored here. | scripts/mp/common.sh | 61 | | MOUNT_DST | /canonical/labs/cicd | The location inside of the VM of the mounted host directory. This will be forwarded to microk8s/kubernetes for use as a persistent volume. | scripts/mp/common.sh | 62 | | --- | --- | --- | --- | 63 | 64 | 65 | # Distributed 66 | 67 | (__TBD__) 68 | -------------------------------------------------------------------------------- /scripts/cicd-tools/add-gitlab.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit immediately on error 4 | set -u # fail on undeclared variables 5 | 6 | ## 7 | ## Install GitLab .. 8 | ## 9 | 10 | ## NB: This assumes the user adds the following to /etc/hosts in host (ie not VM) 11 | ## http.gitlab.labs 12 | ## gitlab.labs 13 | 14 | helm install --name my-gitlab --set externalUrl=http://gitlab.labs/,gitlabRootPassword=pass1234 stable/gitlab-ce 15 | 16 | # Ensure kubernetes is running properly 17 | echo "Checking gitlab is running.." 18 | 19 | until [[ `kubectl get pods --all-namespaces | grep -o 'ContainerCreating' | wc -l` == 0 ]] ; do 20 | echo "Waiting for all pods to be ready, sleeping 10s ("`kubectl get pods --all-namespaces | grep -o 'ContainerCreating' | wc -l`" not running)" 21 | sleep 10 22 | done 23 | 24 | 25 | ## TODO: There is most likely a setting to use NodePort .. pass that in above and remove 26 | ## this command. The default is LoadBalancer, which doesn't make sense localy. 27 | kubectl patch svc my-gitlab-gitlab-ce --type='json' -p '[{"op":"replace","path":"/spec/type","value":"NodePort"}]' 28 | 29 | ## 30 | ## Add the HTTP portion of gitlab to ingress 31 | ## TODO: Ports 22 and 443 are also mapped .. add those to enable other git protocols 32 | echo " 33 | apiVersion: extensions/v1beta1 34 | kind: Ingress 35 | metadata: 36 | name: gitlab-ingress 37 | annotations: 38 | nginx.ingress.kubernetes.io/ssl-redirect: \"false\" 39 | spec: 40 | rules: 41 | - host: http.gitlab.labs 42 | http: 43 | paths: 44 | - path: / 45 | backend: 46 | serviceName: my-gitlab-gitlab-ce 47 | servicePort: 80 48 | " | kubectl apply -f - 49 | -------------------------------------------------------------------------------- /scripts/cicd-tools/add-helm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit immediately on error 4 | set -u # fail on undeclared variables 5 | 6 | ## 7 | ## Install Helm .. 8 | ## 9 | sudo snap install helm --classic 10 | helm init 11 | -------------------------------------------------------------------------------- /scripts/cicd-tools/add-jenkins.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit immediately on error 4 | set -u # fail on undeclared variables 5 | 6 | ## 7 | ## First install the jx tool if it doesn't exist 8 | ## 9 | 10 | mkdir -p ~/.jx/bin 11 | curl -L https://github.com/jenkins-x/jx/releases/download/v1.3.556/jx-linux-amd64.tar.gz | tar xzv -C ~/.jx/bin 12 | PATH=$PATH:~/.jx/bin 13 | ## The following should already be in .bashrc via the cloud.init file 14 | # echo 'export PATH=$PATH:~/.jx/bin' >> ~/.bashrc 15 | 16 | 17 | ## 18 | ## Now use jx to install jenkins into the k8s cluster 19 | ## 20 | jx install --provider=kubernetes --on-premise 21 | jx create quickstart -l go 22 | -------------------------------------------------------------------------------- /scripts/cicd-tools/add-local-storage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit immediately on error 4 | set -u # fail on undeclared variables 5 | 6 | # Grab the directory of the scripts, in case the script is invoked from a different path 7 | SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" 8 | # Useful routines in common.sh 9 | . "${SCRIPTS_DIR}/common-cicd.sh" 10 | CONFIG_DIR=${CONFIG_DIR:-"${SCRIPTS_DIR}/configs"} 11 | TEMPLATE_DIR=${TEMPLATE_DIR:-"${SCRIPTS_DIR}/templates"} 12 | 13 | ##################################################################################### 14 | # 15 | # Associate local storage with the kubernetes cluster. Initially used by the container 16 | # registry, but most likely extended to other uses as well. 17 | # 18 | ##################################################################################### 19 | 20 | ## Use the variables above to replace the template variables .. ie realize the real yamls 21 | cp -f ${TEMPLATE_DIR}/*.yaml ${CONFIG_DIR} 22 | sed -i'.orig' -e `echo s/\$\{\{storage.class.name}}/${SNAME}/g` ${CONFIG_DIR}/*.yaml 23 | # NB: since the path may have '/', I'm using '^' as the sed delimiter 24 | sed -i'.orig' -e `echo s^\$\{\{storage.path}}^${SPATH}^g` ${CONFIG_DIR}/*.yaml 25 | sed -i'.orig' -e `echo s/\$\{\{storage.node}}/${SNODE}/g` ${CONFIG_DIR}/*.yaml 26 | sed -i'.orig' -e `echo s/\$\{\{storage.capacity.pv}}/${PV_MAX}/g` ${CONFIG_DIR}/*.yaml 27 | sed -i'.orig' -e `echo s/\$\{\{storage.capacity.pvc}}/${PVC_MAX}/g` ${CONFIG_DIR}/*.yaml 28 | sed -i'.orig' -e `echo s/\$\{\{storage.pv.name}}/${PV_NAME}/g` ${CONFIG_DIR}/*.yaml 29 | sed -i'.orig' -e `echo s/\$\{\{storage.pvc.name}}/${PVC_NAME}/g` ${CONFIG_DIR}/*.yaml 30 | 31 | ## Now we are ready to apply those yamls to kubernetes 32 | 33 | kubectl create -f ${CONFIG_DIR}/storage_class.yaml 34 | kubectl create -f ${CONFIG_DIR}/persistent_volume.yaml 35 | kubectl create -f ${CONFIG_DIR}/pv_claim.yaml 36 | 37 | ## Print the information: 38 | printf "\nGetting the Persistent Volume Status:\n" 39 | kubectl get pv 40 | #kubectl get pv ${PV_NAME} 41 | 42 | printf "\nGetting the PV Claim Status:\n" 43 | kubectl get pvc 44 | #kubectl get pvc ${PVC_NAME} 45 | -------------------------------------------------------------------------------- /scripts/cicd-tools/add-nexus.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit immediately on error 4 | set -u # fail on undeclared variables 5 | 6 | ## 7 | ## Install Nexus .. 8 | ## 9 | -------------------------------------------------------------------------------- /scripts/cicd-tools/add-spinnaker.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit immediately on error 4 | set -u # fail on undeclared variables 5 | 6 | ## 7 | ## Install Spinnaker 8 | ## 9 | -------------------------------------------------------------------------------- /scripts/cicd-tools/common-cicd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ###################### 4 | ## Common Variables ## 5 | ###################### 6 | 7 | # colors for printing 8 | RED='\033[1;31m' 9 | BLUE='\033[0;36m' 10 | NC='\033[0m' # No Color 11 | 12 | # Storage names and sizing 13 | ## Key Variables, with defaults, that can be overwritten 14 | SNAME=${SNAME:-"local.storage"} 15 | SPATH=${SPATH:-"/canonical/labs/cicd/storage/"} 16 | # the node name for microk8s is the same as the host name .. could make more generic 17 | # by fetching the node name field from kubectl get node 18 | SNODE=${SNODE:-${HOSTNAME}} 19 | PV_NAME=${PV_NAME:-"${SNAME}.pv"} 20 | PV_MAX=${PV_MAX:-300Gi} 21 | # Default the claim to be able to use the entire PV. 22 | PVC_NAME=${PVC_NAME:-"${SNAME}.pvc"} 23 | PVC_MAX=${PVC_MAX:-100Gi} 24 | #PVC_MAX=${PVC_MAX:-${PV_MAX}} 25 | 26 | ###################### 27 | ## Common Functions ## 28 | ###################### 29 | 30 | function info() { 31 | printf "${BLUE}${@}${NC}\n" 32 | } 33 | 34 | function error() { 35 | printf "${RED}${@}${NC}\n" 36 | } 37 | 38 | # Print the error ($2) and exit with status code ($1) 39 | function exit_error() { 40 | error $@ 41 | exit 1 42 | } 43 | 44 | # Ensure we run as root .. 45 | function ensure_root() { 46 | if [[ $EUID -ne 0 ]]; then 47 | error "This script should run using sudo or as the root user" 48 | exit 1 49 | fi 50 | } 51 | 52 | # used primarily to run a cached file if it exists .. 53 | function files_exist() { 54 | ls $1 &>/dev/null 55 | echo $? 56 | } 57 | 58 | # If a cached snap exists, use it, otherwise download from the Internet. 59 | # If using confinement, channel has to be passed in, since it is assumed to be $2 60 | function install_snap() { 61 | local snap_name=$1 62 | local snap_wildcard="${SCRIPTS_DIR}/snaps/${snap_name}*" 63 | local channel=${2:-""} 64 | local confinement=${3:-""} 65 | if [[ $(files_exist ${snap_wildcard}) == 0 ]]; then 66 | info "Install ${snap_name} ${confinement} from cache.." 67 | snap ack ${snap_wildcard}.assert 68 | snap install ${snap_wildcard}.snap ${confinement} 69 | else 70 | info "Install ${snap_name} ${channel} ${confinement} from Internet.." 71 | snap install ${snap_name} ${channel} ${confinement} 72 | fi 73 | } 74 | -------------------------------------------------------------------------------- /scripts/cicd-tools/configs/README.md: -------------------------------------------------------------------------------- 1 | CONFIGS 2 | ======= 3 | 4 | This directory will hold yaml files after applying values to the templates. 5 | The templates have a few variables, like volume size and location, that need to be 6 | specified. 7 | 8 | NB: Please do not put any yaml files in this directory, as they most likely could be 9 | deleted. This directory is populated by the yaml files in the template directory. 10 | -------------------------------------------------------------------------------- /scripts/cicd-tools/del-local-storage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -u # fail on undeclared variables 4 | 5 | # Grab the directory of the scripts, in case the script is invoked from a different path 6 | SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" 7 | # Useful routines in common.sh 8 | . "${SCRIPTS_DIR}/common-cicd.sh" 9 | CONFIG_DIR=${CONFIG_DIR:-"${SCRIPTS_DIR}/configs"} 10 | 11 | printf "\nDeleting the PV Claim '${PVC_NAME}':\n" 12 | kubectl delete -f ${CONFIG_DIR}/pv_claim.yaml &>/dev/null 13 | kubectl get pvc 14 | 15 | printf "\nDeleting the Persistent Volume '${PV_NAME}':\n" 16 | kubectl delete -f ${CONFIG_DIR}/persistent_volume.yaml &>/dev/null 17 | kubectl get pv 18 | 19 | printf "\nDeleting the Storage Class '${SNAME}':\n" 20 | kubectl delete -f ${CONFIG_DIR}/storage_class.yaml &>/dev/null 21 | kubectl get sc 22 | -------------------------------------------------------------------------------- /scripts/cicd-tools/download-snaps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ################################################################################## 4 | ## If you plan on re-creating the stack frequently, or want to fix the version of 5 | ## the snaps you are running, then consider downloading them. 6 | ## 7 | ## install-microk8s will use the cached versions if they exist 8 | ################################################################################## 9 | 10 | # Grab the directory of the scripts, in case the script is invoked from a different path 11 | SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" 12 | # Useful routines in common.sh 13 | . "${SCRIPTS_DIR}/common-cicd.sh" 14 | SNAPS_DIR="${SCRIPTS_DIR}/snaps" 15 | 16 | # If you want a particular version, you can look at info, eg 'snap info microk8s' 17 | # From that info, you can do something like 'snap download microk8s --channel=<>' 18 | mkdir -p "${SNAPS_DIR}" 19 | cd "${SNAPS_DIR}" 20 | snap download core 21 | snap download kubectl 22 | snap download microk8s 23 | -------------------------------------------------------------------------------- /scripts/cicd-tools/expose-dashboard.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -u # fail on undeclared variables 4 | 5 | #################################################################################### 6 | # 7 | # Running this script on the server will do the following: 8 | # 1) Run kubectl proxy 9 | # 2) Add an RBAC account and cluster role binding for access 10 | # 3) Print the token for that relationship (to be used in the UI) 11 | # 4) Print the URL to use. 12 | # 13 | #################################################################################### 14 | 15 | 16 | 17 | PROXY_PORT=${PROXY_PORT:-8001} 18 | LOCAL_ADDR=${LOCAL_ADDR:-'0.0.0.0'} 19 | 20 | # Ensure the port is open .. otherwise assume this script has already executed 21 | PORT_STATUS=`sudo netstat -tulpn | grep ${PROXY_PORT}` &>/dev/null 22 | # PORT_STATUS has text if port open; hence fail -z; || clause will run 23 | if ! [ -z "$PORT_STATUS" ] ; then 24 | echo "Port ${PROXY_PORT} is already used. Exiting" 25 | echo "Process: `echo ${PORT_STATUS} | cut -d ' ' -f 7`" 26 | exit 1 27 | fi 28 | 29 | # This command runs the proxy, allowing anyone to connect 30 | kubectl proxy --port=${PROXY_PORT} --accept-hosts='^.*$' --address=${LOCAL_ADDR} & 31 | 32 | # Use the token method for gaining access to the dashboard. This will require some 33 | # setup for RBAC. 34 | 35 | # Create/Update the service account (used in cluster role binding) 36 | cat <:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/ \n" 63 | printf "\nCopy/paste this token into the kubernetes dashboard:\n" 64 | kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep microk8s-admin | awk '{print $1}') | grep token: | cut -d ":" -f 2 | xargs 65 | -------------------------------------------------------------------------------- /scripts/cicd-tools/install-k8s-base.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit immediately on error 4 | set -u # fail on undeclared variables 5 | 6 | # Grab the directory of the scripts, in case the script is invoked from a different path 7 | SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" 8 | # Useful routines in common.sh 9 | . "${SCRIPTS_DIR}/common-cicd.sh" 10 | 11 | ensure_root 12 | install_snap core 13 | install_snap kubectl --stable --classic 14 | ${SCRIPTS_DIR}/install-microk8s.sh 15 | -------------------------------------------------------------------------------- /scripts/cicd-tools/install-microk8s.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit immediately on error 4 | set -u # fail on undeclared variables 5 | 6 | # Grab the directory of the scripts, in case the script is invoked from a different path 7 | SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" 8 | # Useful routines in common.sh 9 | . "${SCRIPTS_DIR}/common-cicd.sh" 10 | 11 | # If snaps have been cached, then use those. Cached snaps facilitate restarts without 12 | # Internet access. But patches won't be auto updated. 13 | # Otherwise, install from the Internet. 14 | function install_kubernetes() { 15 | install_snap microk8s --stable --classic 16 | 17 | # export the kubectl config file in case other tools rely on this 18 | mkdir -p $HOME/.kube 19 | microk8s.kubectl config view --raw > $HOME/.kube/config 20 | echo "Waiting for kubernetes core services to be ready.." 21 | microk8s.status --wait-ready 22 | sudo snap alias microk8s.kubectl kubectl 23 | } 24 | 25 | function install_addons() { 26 | microk8s.enable dns 27 | microk8s.enable dashboard 28 | microk8s.enable ingress 29 | microk8s.enable storage 30 | 31 | # Ensure kubernetes is running properly 32 | echo "Checking kubernetes addons are running.." 33 | 34 | until [[ `kubectl get pods --all-namespaces | grep -o 'ContainerCreating' | wc -l` == 0 ]] ; do 35 | echo "Waiting for kubernetes addon service pods to be ready, sleeping 10s ("`kubectl get pods --all-namespaces | grep -o 'ContainerCreating' | wc -l`" not running)" 36 | sleep 10 37 | done 38 | } 39 | 40 | ## 41 | # Ensure KUBECONFIG is in .bashrc so that other kubernetes tools can use it 42 | # NB: No longer needed (ensuring default lcoation ~/.kube/config instaed).. not used 43 | # 44 | function ensure_kubeconfig() { 45 | grep KUBECONFIG ${HOME}/.bashrc > /dev/null 2>&1 46 | if [ $? -eq 0 ]; then 47 | echo "Skipping adding KUBECONFIG to ~/.bashrc, already exists" 48 | else 49 | echo "Adding KUBECONFIG to ~/.bashrc" 50 | printf "\n\nexport KUBECONFIG=/snap/microk8s/current/client.config\n\n" >> ${HOME}/.bashrc 51 | fi 52 | } 53 | 54 | ensure_root 55 | install_kubernetes 56 | install_addons 57 | 58 | microk8s.kubectl config view --raw > $HOME/.kube/config 59 | sudo snap alias microk8s.kubectl kubectl 60 | -------------------------------------------------------------------------------- /scripts/cicd-tools/templates/persistent_volume.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolume 2 | apiVersion: v1 3 | metadata: 4 | name: ${{storage.pv.name}} 5 | labels: 6 | type: local 7 | spec: 8 | storageClassName: ${{storage.class.name}} 9 | capacity: 10 | storage: ${{storage.capacity.pv}} 11 | accessModes: 12 | - ReadWriteOnce 13 | hostPath: 14 | path: ${{storage.path}} 15 | -------------------------------------------------------------------------------- /scripts/cicd-tools/templates/pv_claim.yaml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: ${{storage.pvc.name}} 5 | spec: 6 | accessModes: 7 | - ReadWriteOnce 8 | storageClassName: ${{storage.class.name}} 9 | resources: 10 | requests: 11 | storage: ${{storage.capacity.pvc}} 12 | -------------------------------------------------------------------------------- /scripts/cicd-tools/templates/storage_class.yaml: -------------------------------------------------------------------------------- 1 | kind: StorageClass 2 | apiVersion: storage.k8s.io/v1 3 | metadata: 4 | name: ${{storage.class.name}} 5 | provisioner: kubernetes.io/no-provisioner 6 | # Choosing immediate since we only have one node. Alternative is 'WaitForFirstConsumer' 7 | volumeBindingMode: Immediate 8 | -------------------------------------------------------------------------------- /scripts/cicd-tools/templates/test-pod.yaml: -------------------------------------------------------------------------------- 1 | ################################################################################## 2 | # 3 | # This pod spec can be used to test that local storage is working. 4 | # To do this, follow these steps after you've ran add-local-storage.sh: 5 | # 1) create an index.html file in your storage directory (ie ${{storage.path}}) 6 | # -- the default location is /canonical/labs/cicd/storage/ 7 | # -- for text, just put (withou quotes): "Hello from Kubernetes Local Storage" 8 | # 2) create pod - `kubectl create -f configs/test-pod.yaml` 9 | # 3) verify pod - `kubectl get pod test-pod` 10 | # 4) login to pod - `kubectl exec -it test-pod -- /bin/bash` 11 | # 5) verify nginx serves by running curl: 12 | # `apt-get update` 13 | # `apt-get install curl` 14 | # `curl localhost` 15 | # `exit` 16 | # 6) You should see the same text you put into index.html 17 | # 7) Delete pod - `kubectl delete -f configs/test-pod.yaml` 18 | # 19 | ################################################################################## 20 | 21 | kind: Pod 22 | apiVersion: v1 23 | metadata: 24 | name: test-pod 25 | spec: 26 | volumes: 27 | - name: test-pod-storage 28 | persistentVolumeClaim: 29 | claimName: ${{storage.pvc.name}} 30 | containers: 31 | - name: test-pv-container 32 | image: nginx 33 | ports: 34 | - containerPort: 80 35 | name: "http-server" 36 | volumeMounts: 37 | - mountPath: "/usr/share/nginx/html" 38 | name: test-pod-storage 39 | -------------------------------------------------------------------------------- /scripts/mp/cloud.init: -------------------------------------------------------------------------------- 1 | 2 | 3 | runcmd: 4 | # Ensure the kubeconfig file defaults to microk8s 5 | -------------------------------------------------------------------------------- /scripts/mp/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ###################### 4 | ## Common Variables ## 5 | ###################### 6 | 7 | VM_IMAGE=${VM_IMAGE:-"bionic"} 8 | SINGLE_VM_NAME=${SINGLE_VM_NAME:-"cicd-single"} 9 | HOME=${HOME:-"temp"} 10 | STORAGE_SRC=${STORAGE_SRC:-"${HOME}/.canonical/labs/cicd/storage"} 11 | ## ** NB: Whereas we allow to override STORAGE_DST .. cicd install scripts rely on this 12 | ## path .. TODO: add this env var to the .bashrc or some global env list 13 | STORAGE_DST=${STORAGE_DST:-"/canonical/labs/cicd/storage"} 14 | ## CICD_SCRIPTS_DST is the location in the VM to place the scripts. The SRC is defined 15 | ## inside of the script mounting the volume (ie create-single-vm.sh) 16 | CICD_SCRIPTS_DST=${CICD_SCRIPTS_DST:-"/canonical/labs/cicd/scripts"} 17 | 18 | # colors for printing 19 | RED='\033[1;31m' 20 | BLUE='\033[0;36m' 21 | NC='\033[0m' # No Color 22 | 23 | 24 | ###################### 25 | ## Common Functions ## 26 | ###################### 27 | 28 | function info() { 29 | printf "${BLUE}${@}${NC}\n" 30 | } 31 | 32 | function error() { 33 | printf "${RED}${@}${NC}\n" 34 | } 35 | 36 | # Print the error ($2) and exit with status code ($1) 37 | function exit_error() { 38 | error $@ 39 | exit 1 40 | } 41 | 42 | 43 | # Exit if multipass doesn't exist 44 | function exit_no_multipass() { 45 | if ! hash multipass &>/dev/null; then 46 | exit_error "Please install mutlipass and ensure it is on your path." 47 | fi 48 | } 49 | 50 | # Return true if the VM exists, false otherwise 51 | function vm_exists() { 52 | multipass list | grep $1 &>/dev/null 53 | return $? 54 | } 55 | 56 | # Ensure the source directory exists. 57 | function ensure_host_storage() { 58 | mkdir -p ${STORAGE_SRC} 59 | } 60 | -------------------------------------------------------------------------------- /scripts/mp/create-single-vm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit immediately on error 4 | set -u # fail on undeclared variables 5 | 6 | # Grab the directory of the scripts, in case the script is invoked from a different path 7 | SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" 8 | # Useful routines in common.sh 9 | . "${SCRIPTS_DIR}/common.sh" 10 | 11 | CICD_SCRIPTS_SRC=${CICD_SCRIPTS_SRC:-"${SCRIPTS_DIR}/../cicd-tools"} 12 | CLOUD_INIT=${CLOUD_INIT:-"${SCRIPTS_DIR}/cloud.init"} 13 | VM_MEM=${VM_MEM:-12G} 14 | VM_DISK=${VM_DISK:-50G} 15 | VM_CPUS=${VM_CPUS:-4} 16 | 17 | # need mutlipass to launch the vm 18 | exit_no_multipass 19 | 20 | # Only create the VM if it doesn't exist 21 | if vm_exists ${SINGLE_VM_NAME} ; then 22 | exit_error "${SINGLE_VM_NAME} already exists! Exiting." 23 | else 24 | info "CREATING ${SINGLE_VM_NAME}" 25 | multipass launch \ 26 | --name ${SINGLE_VM_NAME} \ 27 | --mem ${VM_MEM} \ 28 | --disk ${VM_DISK} \ 29 | --cpus ${VM_CPUS} \ 30 | --cloud-init ${CLOUD_INIT} \ 31 | ${VM_IMAGE} 32 | # Where "permanent data" will be stored 33 | info "MOUNTING HOST:${STORAGE_SRC} --> VM:${STORAGE_DST}" 34 | ensure_host_storage 35 | multipass mount ${STORAGE_SRC} ${SINGLE_VM_NAME}:${STORAGE_DST} 36 | 37 | # Where the scripts are stored 38 | info "MOUNTING HOST:${CICD_SCRIPTS_SRC} --> VM:${CICD_SCRIPTS_DST}" 39 | multipass mount ${CICD_SCRIPTS_SRC} ${SINGLE_VM_NAME}:${CICD_SCRIPTS_DST} 40 | fi 41 | -------------------------------------------------------------------------------- /scripts/mp/destroy-single-vm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit immediately on error 4 | set -u # fail on undeclared variables 5 | 6 | # In case the script is invoked from a different directory, grab mine 7 | SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" 8 | # Useful routines in common.sh 9 | . "${SCRIPTS_DIR}/common.sh" 10 | 11 | exit_no_multipass 12 | 13 | # Only clean the VM if it exists 14 | if vm_exists ${SINGLE_VM_NAME} ; then 15 | info "Deleting and purging VM '${SINGLE_VM_NAME}'." 16 | multipass delete ${SINGLE_VM_NAME} 17 | multipass purge 18 | else 19 | info "The VM ${SINGLE_VM_NAME} does **not** exist." 20 | fi 21 | -------------------------------------------------------------------------------- /scripts/mp/ssh-single-vm.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e # exit immediately on error 4 | set -u # fail on undeclared variables 5 | 6 | # Grab the directory of the scripts, in case the script is invoked from a different path 7 | SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" 8 | # Useful routines in common.sh 9 | . "${SCRIPTS_DIR}/common.sh" 10 | 11 | multipass shell ${SINGLE_VM_NAME} 12 | --------------------------------------------------------------------------------