commit 76aebc9f9ed036af3a2afef2fd304bcc80975b3a Author: Chris Wedgwood Date: Tue Aug 1 19:15:26 2017 +0000 Initial commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a763170 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +helm.log +berth-0.1.0.tgz diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..8dada3e --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..982c7e8 --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ +# This Makefile is used during development and can usually be ignored +# by most people. + +all: test + +default: test + +test: install + +install: build + @echo + -helm delete --purge berth >>helm.log 2>&1 + @echo + @[ -f override.yaml ] || touch override.yaml + helm install ./berth-0.1.0.tgz --values=override.yaml --name=berth >>helm.log 2>&1 + @sleep 5.0 # give k8s a chance to see the IP + @echo + kubectl get pods -o wide + +build: + @echo + helm lint berth + @echo + helm package berth + +clean: + rm -f berth-0.1.0.tgz helm.log + +.PHONY: + all default build clean diff --git a/README.md b/README.md new file mode 100644 index 0000000..4a96a8c --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +Berth is a deliberately minimalist VM runner for Kubernetes. + +I'm not 100% sold on the name; before merging we could change it... + +## TL;DR Installation Guide + +``` +# Make sure you have Helm 2.5.x and Kubernetes 1.6.x +# +# edit values.yaml; set class_name and ssh key +# +helm package berth +helm install --name=berth ./berth-0.1.0.tgz # ... +kubectl get pods -o wide +``` + +You should be able to SSH to your VM at the Kubernetes IP for the +container which you can retrieve with `kubectl get all -o wide`. VNC +access is available on port 5900. + +``` +ssh -i ./you-ssh-private-key root@ip.of.vm.pod +``` + + +### Example + +[Quick installation / sample](https://asciinema.org/a/4VazbwsokL3zpnGPf27eyFIfe) + +### Why this? + +The requirements are very narrow right now and the existing +alternatives don't align well at present. This will likely change in +time at which point we can realign the internal implementation. + +#### Minimalist requirements +* Run VMs from inside of Kubernetes +* Work with Calico +* Have VM life-cycle match that of pods +* Have VMs benefit from Kubernetes resiliency +* Allow for persistent storage +* Allow for state injection/access from a ConfigMaps + +## Requirements: +* Helm 2.5.x +* Kubernetes 1.6.x + +This does not need to be installed as part of the OpenStack chart +collection. + +## How it works: + +At a high level, it works like this: +* Create a SNAT/DNAT enabled linux bridge. +* Assign the bridge a private IP address from a small /30 subnet + (controlled with `VM_IP` and `VM_GW`) +* Plug the VM network interface into the bridge. +* Run a dnsmasq process to allocate the VM the right name-servers, and + DNS search strings extracted from the parent container. Assign the + private IP address to the VM and have it use the bridges IP as its + default gateway. +* Setup SNAT/DNAT on the parent container to do 1:1 mapping of all + ports, all protocols to the VM, except for TCP:5900 to allow for VNC + access (can be controlled with NO_VNC environment variable). +* At this point, VM essentially assumes Pod Assigned IP. +* Feed any meta-data or user-data down into the VM by leveraging these + ConfigMap mounts with the same name and turning them into an ISO + presented to the guest. + +The startvm entry-point supports several environment variables: + +* `IMG_SOURCE` which is an http or https URL that contains a qcow2 + image. It can also be a full path to a local file baked into the + container image, e.g. "/image.qcow" +* `IMG_TARGET` the name to save the image above as in the shared + volume. + +It also supports two files, which should be mounted as ConfigMaps if +using Kubernetes at `/userdata` and `/metadata` as YAML files +containing, obviously meta-data and user-data as YAML that will be fed +to the VM as a config-drive iso. + +The "pet" version of the image, which is created using qemu-img -b to +base it on the source, is stored in a separate volume dedicated to the +VM itself, and named after the container hostname. + +There are a few other parameters you can control as an operator: + +* `VM_IP` is the IP address the VM should be allocated by DHCP. The + container will 1:1 NAT except for port 5900 for VNC access (defaults + to 192.168.254.2) +* `VM_GW` is the gateway IP address the VM should use for its default + route (defaults to 192.168.254.1) diff --git a/TODO b/TODO new file mode 100644 index 0000000..cd21407 --- /dev/null +++ b/TODO @@ -0,0 +1,23 @@ +[Put these in Jira] + +*Require* ssh key, throw an error if missing. + +Chart definition vs values.yaml: + + Move image source/target details from chart to values + (IMG_SOURCE/IMG_TARGET) + + Move the VM definitions entirely into the values.yaml file; have + helm deployment process iterate over that creating multiple pods, + one for each VM. + + Ideally this will allow incremental updates of pods without having + to know about the chart internals. + + XXX Get examples of where we've done this before from Alan XXX + +Add Dockerfile; update the container image we use to Ubuntu 16.04 with +a suitable KVM/Qemu. + +Consider moving to stateful sets for cleaner PVC associations. See +OSH MariaDB chart for an example of this. diff --git a/berth/Chart.yaml b/berth/Chart.yaml new file mode 100644 index 0000000..90ada71 --- /dev/null +++ b/berth/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +description: Minimalist VMs on Kubernetes +name: berth +version: 0.1.0 +icon: https://upload.wikimedia.org/wikipedia/commons/6/62/Anchor_pictogram.svg diff --git a/berth/requirements.yaml b/berth/requirements.yaml new file mode 100644 index 0000000..32cf5dd --- /dev/null +++ b/berth/requirements.yaml @@ -0,0 +1 @@ +dependencies: [] diff --git a/berth/templates/bin/_startvm.txt b/berth/templates/bin/_startvm.txt new file mode 100755 index 0000000..52f1efe --- /dev/null +++ b/berth/templates/bin/_startvm.txt @@ -0,0 +1,261 @@ +#!/bin/bash + +set -x + +echo "VER-0.1.0-1.2" + +# Returns the integer representation of an IP arg, passed in ascii +# dotted-decimal notation (x.x.x.x) +atoi() { + IP=$1; IPNUM=0 + for (( i=0 ; i<4 ; ++i )); do + ((IPNUM+=${IP%%.*}*$((256**$((3-${i})))))) + IP=${IP#*.} + done + echo $IPNUM +} + +# Returns the dotted-decimal ascii form of an IP arg passed in integer +# format +itoa() { + echo -n $(($(($(($((${1}/256))/256))/256))%256)). + echo -n $(($(($((${1}/256))/256))%256)). + echo -n $(($((${1}/256))%256)). + echo $((${1}%256)) +} + +generate_cloud_drive() { + metadata=/metadata + if [ ! -f $metadata ]; then + metadata="" + fi + + userdata=/userdata + if [ ! -f $userdata ]; then + userdata="" + fi + + if [ "$metadata" == "" -a "$userdata" == "" ]; then + return + fi + + TMPDIR=`mktemp -d -t aicvm.XXXXXX` + + if [ $? -ne 0 ]; then + echo "Fail to create temporaily directory" + exit 1 + fi + + # create form of config drive + mkdir -p ${TMPDIR}/openstack/2012-08-10 + OLD_PWD=$PWD + cd ${TMPDIR}/openstack + ln -s 2012-08-10 latest + cd $OLD_PWD + + if [ -f $metadata ]; then + cp $metadata ${TMPDIR}/openstack/2012-08-10/meta_data.json + fi + if [ -f $userdata ]; then + cp $userdata ${TMPDIR}/openstack/2012-08-10/user_data + fi + + iso="cloud-drive.iso" + mkisofs -R -V config-2 -o $iso ${TMPDIR} + if [ $? -ne 0 ]; then + echo Fail to create cloud-drive ISO image for cloud-init + exit 1 + fi + echo $iso +} + +# Generate random new MAC address +hexchars="0123456789ABCDEF" +end=$( for i in {1..8} ; do echo -n ${hexchars:$(( $RANDOM % 16 )):1} ; done | sed -e 's/\(..\)/:\1/g' ) +NEWMAC=`echo 06:FE$end` + +# These two variables can be overwritten +: ${KVM_BLK_OPTS:="-drive file=\$KVM_IMAGE,if=none,id=drive-disk0,format=qcow2 \ +-device virtio-blk-pci,scsi=off,drive=drive-disk0,id=virtio-disk0,bootindex=1"} +: ${KVM_RAW_BLK_OPTS:="-drive file=\$KVM_IMAGE,if=none,id=drive-disk0,format=raw \ +-device virtio-blk-pci,scsi=off,drive=drive-disk0,id=virtio-disk0,bootindex=1"} +: ${KVM_NET_OPTS:="-netdev bridge,br=\$BRIDGE_IFACE,id=net0 \ +-device virtio-net-pci,netdev=net0,mac=\$NEWMAC"} + +# define some valeus for the VM side of the networking but +# allow them to be overriden by the operator +: ${VM_IP:="192.168.254.2"} +: ${VM_GW:="192.168.254.1"} + +# the netmask is not definable, as we leverage +# /30 elsewhere +VM_NETMASK="255.255.255.252" + +# For debugging +if [ "$1" = "bash" ]; then + exec bash +fi + +# Pass Docker command args to kvm +KVM_ARGS=$@ + +# Create the qcow disk image on the Docker volume named /image, using +# the compressed qcow image that came with Docker image as the base. +# Docker volumes typically perform better than the file system for +# Docker images (no need for overlay fs etc.) + +if [ -e /dev/vm/root ]; then + KVM_BLK_OPTS="$KVM_RAW_BLK_OPTS" + KVM_IMAGE=/dev/vm/root +else + + if [ -e "${IMG_TARGET}" ]; then + BASE=${IMG_TARGET} + else + + if [ ! -d "/image" ]; then + echo "/image directory does not exist, failed to mount volume?" + exit 2 + fi + + if [ ! -e "/image/${IMG_TARGET}" ]; then + echo "Fetching missing image target" + curl ${IMG_SOURCE} > /image/${IMG_TARGET} + fi + + BASE=/image/${IMG_TARGET} + fi + + if [ ! -d "/image" ]; then + echo "/image directory does not exist, failed to mount volume /image?" + exit 2 + fi + + if [ -z "${HOSTNAME}" ]; then + echo "Could not find HOSTNAME var. Did you specify a HOSTNAME environment variable?" + fi + + KVM_IMAGE=/image/${HOSTNAME}.qcow2 + + if [ -e "${KVM_IMAGE}" ]; then + echo "Image ${KVM_IMAGE} already exists. Not recreating" + else + qemu-img create -f qcow2 -b ${BASE} \ + $KVM_IMAGE > /dev/null + if [[ $? -ne 0 ]]; then + echo "Failed to create qcow2 image" + exit 3 + fi + fi +fi + +VOLUMES_DIR="/volumes/" +VOLUMES_LIST=`find $VOLUMES_DIR -name "*.img" | sort -d` +extra_kvm_blk_opts="" +for volume in $VOLUMES_LIST /dev/vm/disk* ; do + if [ -e $volume ]; then + extra_kvm_blk_opts=$extra_kvm_blk_opts" -drive file=$volume,if=virtio,format=raw" + fi +done +KVM_BLK_OPTS=$KVM_BLK_OPTS$extra_kvm_blk_opts + +# Network setup: +# +# 1. Create a bridge named br0 +# 2. Remove IP from eth0, save eth0 MAC, give eth0 a random MAC + +IFACE=eth0 +BRIDGE_IFACE=br0 + +cidr2mask() { + local i mask="" + local full_octets=$(($1/8)) + local partial_octet=$(($1%8)) + + for ((i=0;i<4;i+=1)); do + if [ $i -lt $full_octets ]; then + mask+=255 + elif [ $i -eq $full_octets ]; then + mask+=$((256 - 2**(8-$partial_octet))) + else + mask+=0 + fi + test $i -lt 3 && mask+=. + done + + echo $mask +} + +setup_bridge_networking() { + + MAC=`ip addr show $IFACE | grep ether | sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*\$//g' | cut -f2 -d ' '` + HOST_IP=`ip addr show dev $IFACE | grep "inet $IP" | awk '{print $2}' | cut -f1 -d/` + HOST_CIDR=`ip addr show dev $IFACE | grep "inet $IP" | awk '{print $2}' | cut -f2 -d/` + HOST_NETMASK=`cidr2mask $HOST_CIDR` + HOST_GATEWAY=`ip route get 8.8.8.8 | grep via | cut -f3 -d ' '` + NAMESERVER=( `grep nameserver /etc/resolv.conf | grep -v "#" | cut -f2 -d ' '` ) + NAMESERVERS=`echo ${NAMESERVER[*]} | sed "s/ /,/"` + SEARCH=( `grep -E ^search /etc/resolv.conf | grep -v "#" | cut -f2- -d ' ' | tr ' ' ','` ) + + # we must enable forwarding inside the container + echo 1 > /proc/sys/net/ipv4/ip_forward + + # we support exposing port 5900 on the container but leave + # it up to the operator on whether to expose this - they can + # specify NO_VNC as an environment variable to disable this + # functionality + if [ -z $NO_VNC ]; then + iptables -t nat -A PREROUTING -p tcp \! --dport 5900 -d $HOST_IP -j DNAT --to-destination $VM_IP + iptables -t nat -A POSTROUTING -s $VM_IP -j SNAT --to-source $HOST_IP + else + iptables -t nat -A PREROUTING -d $HOST_IP -j DNAT --to-destination $VM_IP + iptables -t nat -A POSTROUTING -s $VM_IP -j SNAT --to-source $HOST_IP + fi + + # generate VM specifics + cat > /etc/dnsmasq.conf << EOF +user=root +dhcp-range=$VM_IP,$VM_IP +dhcp-host=$NEWMAC,$HOSTNAME,$VM_IP,infinite +dhcp-option=option:router,$VM_GW +dhcp-option=option:netmask,$VM_NETMASK +dhcp-option=option:dns-server,$NAMESERVERS +dhcp-option=119,$SEARCH +EOF + + if [ -z $NO_DHCP ]; then + dnsmasq + fi + + brctl addbr $BRIDGE_IFACE + ip link set dev $BRIDGE_IFACE up + ip addr add $VM_GW/30 dev $BRIDGE_IFACE + + # alanmeadows(NOTE) in many implementations with out of + # subnet gateways the dhcp approach does not work + # if [ -z $NO_DHCP ]; then + # ip addr add $NEWIP/$NEWCIDR dev $BRIDGE_IFACE + # fi + + if [[ $? -ne 0 ]]; then + echo "Failed to bring up network bridge" + exit 4 + fi + + # Exec kvm as PID 1 + mkdir -p /etc/qemu + echo allow $BRIDGE_IFACE > /etc/qemu/bridge.conf +} + +# need to wait until network is ready +ISO=`generate_cloud_drive` +if [[ $ISO ]]; then + KVM_BLK_OPTS=$KVM_BLK_OPTS" -cdrom $ISO" +fi + +setup_bridge_networking + +HOST_IP=`ip addr show dev $IFACE | grep "inet $IP" | awk '{print $2}' | cut -f1 -d/` +VNC="-vnc $HOST_IP:0" + +exec $LAUNCHER qemu-system-x86_64 -enable-kvm $VNC `eval echo $KVM_BLK_OPTS` `eval echo $KVM_NET_OPTS` -usbdevice tablet -nographic $KVM_ARGS diff --git a/berth/templates/deployment.yaml b/berth/templates/deployment.yaml new file mode 100644 index 0000000..52ed2aa --- /dev/null +++ b/berth/templates/deployment.yaml @@ -0,0 +1,132 @@ +# FIXME(cw); refactor into multiple per-function files + +# FIXME(cw) consider using OSH helm-toolkit.utils.template +{{- define "template" -}} +{{- $name := index . 0 -}} +{{- $context := index . 1 -}} +{{- $last := base $context.Template.Name }} +{{- $wtf := $context.Template.Name | replace $last $name -}} +{{ include $wtf $context }} +{{- end -}} + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: cloudinit +data: + metadata: | + { "uuid": "example-01-vm.mydomain.com" } + userdata: | + #cloud-config + fqdn: example-01-vm.mydomain.com + users: + - name: root + ssh-authorized-keys: + - {{ .Values.auth.ssh_key }} + ssh_pwauth: True + runcmd: + - [ apt-get, update ] + - [ apt-get, install, -y, --force-yes, apache2 ] +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: configmap-startvm +data: + startvm: | + #!/bin/bash + # + # start of startvm +{{ tuple "bin/_startvm.txt" . | include "template" | indent 4 }} + # end of startvm +--- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: example-01-vm +spec: + accessModes: [ "ReadWriteOnce" ] + resources: + requests: + storage: {{ .Values.volume.size }} +{{ if not .Values.volume.class_name }} + storageClassName: {{ .Values.volume.class_name }} +{{ end }} +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: berth +spec: + replicas: 1 + template: + metadata: + labels: + app: berth + annotations: + pod.beta.kubernetes.io/hostname: example-01-vm + spec: + nodeSelector: + {{ .Values.labels.node_selector_key }}: {{ .Values.labels.node_selector_value }} + hostNetwork: false + hostPID: false + securityContext: + runAsUser: 0 + containers: + - name: example-01-vm + imagePullPolicy: IfNotPresent + image: {{ .Values.images.entrypoint }} + env: + - name: IMG_SOURCE + value: http://stupidest.org/vm/ubuntu-14.04-amd64.img + - name: IMG_TARGET + value: ubuntu-14.04-amd64.img + securityContext: + privileged: true + command: + - /usr/local/bin/startvm + ports: + - containerPort: {{ .Values.network.port }} + - containerPort: {{ .Values.network.vnc }} + readinessProbe: + tcpSocket: + port: {{ .Values.network.vnc }} + volumeMounts: + - name: volume-startvm + mountPath: /usr/local/bin/startvm + subPath: startvm + - name: image + mountPath: /image + - name: dev + mountPath: /dev + - name: sys + mountPath: /sys + - name: cloudinit + mountPath: /userdata + subPath: userdata + - name: cloudinit + mountPath: /metadata + subPath: metadata + volumes: + - name: volume-startvm + configMap: + name: configmap-startvm + defaultMode: 0755 + - name: image + persistentVolumeClaim: + claimName: example-01-vm + - name: dev + hostPath: + path: /dev + - name: sys + hostPath: + path: /sys + - name: cloudinit + configMap: + name: cloudinit + items: + - key: userdata + path: userdata + - key: metadata + path: metadata diff --git a/berth/values.yaml b/berth/values.yaml new file mode 100644 index 0000000..58b1402 --- /dev/null +++ b/berth/values.yaml @@ -0,0 +1,18 @@ + +auth: + ssh_key: + +images: + entrypoint: quay.io/attcomdev/kvm-manager:latest + +labels: + node_selector_key: openstack-control-plane + node_selector_value: enabled + +volume: + class_name: + size: 25Gi + +network: + port: 22 + vnc: 5900