diff --git a/control-shell.sh b/control-shell.sh index 501357195822c8a3067bc5d55b945decf888164d..fb03b3602ff782ac5ec83c32fd79e8f3031b234c 100755 --- a/control-shell.sh +++ b/control-shell.sh @@ -11,5 +11,5 @@ docker run --rm -it \ --hostname=control \ -v /oas:/oas \ -v /oas/local/control:/control/local \ - docker.greenhost.net/openappstack/control \ + docker.greenhost.net/openappstack/bootstrap/control \ $command diff --git a/control/Dockerfile b/control/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..6aa9ab612d1c8bbc5e52a81236a6fb751e0e6497 --- /dev/null +++ b/control/Dockerfile @@ -0,0 +1,19 @@ +FROM linuxbrew/linuxbrew +MAINTAINER arie@greenhost.nl + +RUN brew update +ADD brew/kubernetes-cli.rb /brew/kubernetes-cli.rb +RUN brew install /brew/kubernetes-cli.rb +RUN brew install kubernetes-helm helmfile +RUN mkdir -p $HOME/.helm/plugins && \ + helm plugin install https://github.com/databus23/helm-diff +ADD bin/rke /control/bin/ +ADD control /control/bin/ +ADD cluster.yml.template /control/data/ +ADD k8s-config/ /control/k8s-config +ADD bashrc /control/.bashrc +USER root +ENV PATH="/control/bin:${PATH}" \ + HOME="/oas" \ + HELM_HOME="/control/local/helm" \ + KUBECONFIG="/control/local/kube/config" diff --git a/control/README.md b/control/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8a8b589626b31eed8b76dd2ebf504ac464c80e8c --- /dev/null +++ b/control/README.md @@ -0,0 +1,4 @@ +This folder contains the files necessary to make the `control` docker container. + +This container can be used to manage your Kubernetes cluster from a container +*within kubernetes*. diff --git a/control/bashrc b/control/bashrc new file mode 100644 index 0000000000000000000000000000000000000000..2a1000c9db76b2f108f517ad5d2f6546de76b473 --- /dev/null +++ b/control/bashrc @@ -0,0 +1,24 @@ +#!/bin/bash + +export PS1="\[\e[1;31m\]control shell \$\[\e[0m\] " + +pluginPath="$HELM_HOME/plugins/helm-diff" +if ! [ -e "$pluginPath" ] +then + # Create a symlink to the helm-diff plugin which was installed in the + # docker image. + ln -s "/home/linuxbrew/.helm/plugins/helm-diff" "$pluginPath" +fi + +cd + +echo 'This is the "control" docker image for managing your oas cluster.' +echo 'The following programs are available to view and administer the cluster:' +echo ' kubectl' +echo ' helm' +echo ' helmfile' + +echo 'These are the currently installed helm releases:' +echo '======== `helm ls`' +helm ls +echo '========' diff --git a/control/bin/rke b/control/bin/rke new file mode 100755 index 0000000000000000000000000000000000000000..8abf7099f9f76bde69ab67eabc339d8df3fdface Binary files /dev/null and b/control/bin/rke differ diff --git a/control/brew/kubernetes-cli.rb b/control/brew/kubernetes-cli.rb new file mode 100644 index 0000000000000000000000000000000000000000..41972efb54314dccb7b8fa945d51d15618d0cddb --- /dev/null +++ b/control/brew/kubernetes-cli.rb @@ -0,0 +1,59 @@ +class KubernetesCli < Formula + desc "Kubernetes command-line interface" + homepage "https://kubernetes.io/" + url "https://github.com/kubernetes/kubernetes.git", + :tag => "v1.12.2", + :revision => "17c77c7898218073f14c8d573582e8d2313dc740" + head "https://github.com/kubernetes/kubernetes.git" + + bottle do + cellar :any_skip_relocation + sha256 "3aa43db83e2181069bc3faca3ff83d9e724272d689047a8b4c648168e67b2bc4" => :mojave + sha256 "23a10b46914920291f84bff6cd7ca725f9f13b4e72d055a6200989602c973c1c" => :high_sierra + sha256 "908d289d262b55d3331e1d6f3b335297622299869d1d1705c9fa56ed58702d4d" => :sierra + end + + depends_on "go" => :build + depends_on "rsync" => :build unless OS.mac? + + def install + ENV["GOPATH"] = buildpath + os = OS.linux? ? "linux" : "darwin" + arch = MacOS.prefer_64_bit? ? "amd64" : "x86" + dir = buildpath/"src/k8s.io/kubernetes" + dir.install buildpath.children - [buildpath/".brew_home"] + + cd dir do + # Race condition still exists in OS X Yosemite + # Filed issue: https://github.com/kubernetes/kubernetes/issues/34635 + ENV.deparallelize { system "make", "generated_files" } + + # Make binary + system "make", "kubectl" + bin.install "_output/local/bin/#{os}/#{arch}/kubectl" + + # Install bash completion + output = Utils.popen_read("#{bin}/kubectl completion bash") + (bash_completion/"kubectl").write output + + # Install zsh completion + output = Utils.popen_read("#{bin}/kubectl completion zsh") + (zsh_completion/"_kubectl").write output + + prefix.install_metafiles + end + end + + test do + run_output = shell_output("#{bin}/kubectl 2>&1") + assert_match "kubectl controls the Kubernetes cluster manager.", run_output + + version_output = shell_output("#{bin}/kubectl version --client 2>&1") + assert_match "GitTreeState:\"clean\"", version_output + if build.stable? + assert_match stable.instance_variable_get(:@resource) + .instance_variable_get(:@specs)[:revision], + version_output + end + end +end diff --git a/control/cluster.yml.template b/control/cluster.yml.template new file mode 100644 index 0000000000000000000000000000000000000000..35fbc5735aea497b6d14fc173091a683e4dac438 --- /dev/null +++ b/control/cluster.yml.template @@ -0,0 +1,124 @@ +nodes: +- address: $NODE_ADDRESS + # port: "22" + # internal_address: "" + role: + - controlplane + - worker + - etcd + hostname_override: oas + user: root + # docker_socket: /var/run/docker.sock + # ssh_key: "" + ssh_key_path: /oas/config/ssh_key + # labels: {} +services: + etcd: + image: "" + extra_args: {} + extra_binds: [] + extra_env: [] + external_urls: [] + ca_cert: "" + cert: "" + key: "" + path: "" + snapshot: false + retention: "" + creation: "" + kube-api: + image: "" + extra_args: {} + extra_binds: [] + extra_env: [] + service_cluster_ip_range: 10.43.0.0/16 + service_node_port_range: "" + pod_security_policy: false + kube-controller: + image: "" + extra_args: {} + extra_binds: [] + extra_env: [] + cluster_cidr: 10.42.0.0/16 + service_cluster_ip_range: 10.43.0.0/16 + scheduler: + image: "" + extra_args: {} + extra_binds: [] + extra_env: [] + kubelet: + image: "" + extra_args: {} + extra_binds: [] + extra_env: [] + cluster_domain: cluster.local + infra_container_image: "" + cluster_dns_server: 10.43.0.10 + fail_swap_on: false + kubeproxy: + image: "" + extra_args: {} + extra_binds: [] + extra_env: [] +network: + plugin: canal + options: {} +authentication: + strategy: x509 + options: {} + sans: [] +addons: "" +addons_include: [] +system_images: + etcd: rancher/coreos-etcd:v3.2.18 + alpine: rancher/rke-tools:v0.1.15 + nginx_proxy: rancher/rke-tools:v0.1.15 + cert_downloader: rancher/rke-tools:v0.1.15 + kubernetes_services_sidecar: rancher/rke-tools:v0.1.15 + kubedns: rancher/k8s-dns-kube-dns-amd64:1.14.10 + dnsmasq: rancher/k8s-dns-dnsmasq-nanny-amd64:1.14.10 + kubedns_sidecar: rancher/k8s-dns-sidecar-amd64:1.14.10 + kubedns_autoscaler: rancher/cluster-proportional-autoscaler-amd64:1.0.0 + kubernetes: rancher/hyperkube:v1.11.3-rancher1 + flannel: rancher/coreos-flannel:v0.10.0 + flannel_cni: rancher/coreos-flannel-cni:v0.3.0 + calico_node: rancher/calico-node:v3.1.3 + calico_cni: rancher/calico-cni:v3.1.3 + calico_controllers: "" + calico_ctl: rancher/calico-ctl:v2.0.0 + canal_node: rancher/calico-node:v3.1.3 + canal_cni: rancher/calico-cni:v3.1.3 + canal_flannel: rancher/coreos-flannel:v0.10.0 + wave_node: weaveworks/weave-kube:2.1.2 + weave_cni: weaveworks/weave-npc:2.1.2 + pod_infra_container: rancher/pause-amd64:3.1 + ingress: rancher/nginx-ingress-controller:0.16.2-rancher1 + ingress_backend: rancher/nginx-ingress-controller-defaultbackend:1.4 + metrics_server: rancher/metrics-server-amd64:v0.2.1 +ssh_agent_auth: false +authorization: + mode: rbac + options: {} +ignore_docker_version: false +kubernetes_version: "" +private_registries: [] +ingress: + # Set this to none, so we can install traefik ourselves. + provider: none + options: {} + node_selector: {} + extra_args: {} +cluster_name: "" +cloud_provider: + name: "" +prefix_path: "" +addon_job_timeout: 0 +bastion_host: + address: "" + port: "" + user: "" + ssh_key: "" + ssh_key_path: "" +monitoring: + provider: "" + options: {} diff --git a/control/control b/control/control new file mode 100755 index 0000000000000000000000000000000000000000..6ac099ed022f687da6c02307ec2cab7520a2dc86 --- /dev/null +++ b/control/control @@ -0,0 +1,93 @@ +#!/bin/bash + +command=$1 +read -r ip < "/oas/config/ip" + +buildCluster() +{ + echo "Setting up OpenAppStack cluster." + mkdir -p "/control/config" + clusterConfigFile="/control/config/cluster.yml" + cp "/control/data/cluster.yml.template" "$clusterConfigFile" + mkdir -p "${HOME}/.ssh" + sed -i -e "s/\$NODE_ADDRESS/${ip}/" "$clusterConfigFile" + { + echo "# Inserted by OAS control" + ssh-keyscan -H "$ip" 2> /dev/null + } >> "${HOME}/.ssh/known_hosts" + rke up --config="$clusterConfigFile" || exit + mkdir -p "/control/local/kube" + cp "/control/config/kube_config_cluster.yml" "/control/local/kube/config" +} + +installTiller() +{ + kubectl apply -f "/control/k8s-config/tiller-permissions.yml" + helm init --service-account=tiller +} + +createStorage() +{ + pushd "/control/k8s-config/storage" || return + shopt -s nullglob + for yaml in ./*.yaml ./*.yml + do + kubectl apply -f "$yaml" + storageDir=$(grep '/var/local/k8s/[^"]*' -o "$yaml") + ssh -i "/oas/config/ssh_key" "root@${ip}" "mkdir -p \"$storageDir\" && chmod a+w \"$storageDir\"" + done +} + +getRepos() +{ + reposDir="/oas/source/repos" + mkdir -p "$reposDir" + for repo in "helmfiles" "charts" + do + target="${reposDir}/${repo}" + if ! [ -d "$target" ] + then + echo "Getting ${repo}." + git clone "https://code.greenhost.net/openappstack/${repo}" "$target" || exit + else + echo "Already have ${repo}, updating." + pushd "$target" + git pull + popd + fi + done +} + +configureKeycloak() +{ + kubectl create secret generic realm-secret "--from-file=/control/k8s-config/realm.json" +} + +configFiles() +{ + mkdir -p "/oas/config/values/apps" + for app in "traefik keycloak" + do + # Create corresponding file to set extra overriding values. + touch "/oas/config/values/apps/${app}.yaml" + done +} + +helmfile() +{ + helmfile -e oas -f "/oas/source/repos/helmfiles/helmfile.d" apply +} + +case "$command" in + setup) + buildCluster + installTiller + createStorage + getRepos + configureKeycloak + configFiles + helmfile + ;; + *) + $command +esac diff --git a/control/k8s-config/realm.json b/control/k8s-config/realm.json new file mode 100644 index 0000000000000000000000000000000000000000..67f171ab6f335cc002cf0f1bce932e89a53ff1bb --- /dev/null +++ b/control/k8s-config/realm.json @@ -0,0 +1,19 @@ +{ + "realm": "OpenAppStack", + "enabled": true, + "sslRequired": "external", + "registrationAllowed": true, + "requiredCredentials": [ "password" ], + "roles" : { + "realm" : [ + { + "name": "user", + "description": "User privileges" + }, + { + "name": "admin", + "description": "Administrator privileges" + } + ] + } +} diff --git a/control/k8s-config/storage/keycloak-postgres-storage.yml b/control/k8s-config/storage/keycloak-postgres-storage.yml new file mode 100644 index 0000000000000000000000000000000000000000..aaa2932b747dd5f03a225cc6cd4707630c3c8a3a --- /dev/null +++ b/control/k8s-config/storage/keycloak-postgres-storage.yml @@ -0,0 +1,15 @@ +kind: PersistentVolume +apiVersion: v1 +metadata: + name: keycloak-postgres + labels: + type: local +spec: + capacity: + storage: 1Gi + accessModes: + - ReadWriteOnce + persistentVolumeReclaimPolicy: Recycle + hostPath: + path: "/var/local/k8s/keycloak-postgres" + type: DirectoryOrCreate diff --git a/control/k8s-config/storage/traefik-storage.yml b/control/k8s-config/storage/traefik-storage.yml new file mode 100644 index 0000000000000000000000000000000000000000..06f88329e6f2338c3fb609ecb0e64ba9c5232b71 --- /dev/null +++ b/control/k8s-config/storage/traefik-storage.yml @@ -0,0 +1,14 @@ +kind: PersistentVolume +apiVersion: v1 +metadata: + name: traefik-pv-acme + labels: + type: local +spec: + capacity: + storage: 10Mi + accessModes: + - ReadWriteOnce + hostPath: + path: "/var/local/k8s/traefik-pv-acme" + type: DirectoryOrCreate diff --git a/control/k8s-config/tiller-permissions.yml b/control/k8s-config/tiller-permissions.yml new file mode 100644 index 0000000000000000000000000000000000000000..d3ed1ad46e59dc90dfa95857904d4b079777e09a --- /dev/null +++ b/control/k8s-config/tiller-permissions.yml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: tiller + namespace: kube-system +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1beta1 +metadata: + name: tiller-clusterrolebinding +subjects: +- kind: ServiceAccount + name: tiller + namespace: kube-system +roleRef: + kind: ClusterRole + name: cluster-admin + apiGroup: "" diff --git a/get-control.sh b/get-control.sh index e68516283ed2a06e10c059c2cdb56790f23267eb..4f641e3a4f6482ae396067052e1b0e8853d98822 100644 --- a/get-control.sh +++ b/get-control.sh @@ -20,4 +20,4 @@ then fi # Get control docker image. -docker pull "docker.greenhost.net/openappstack/control" +docker pull "docker.greenhost.net/openappstack/bootstrap/control"