Initial commit.
This commit is contained in:
commit
76aebc9f9e
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
helm.log
|
||||
berth-0.1.0.tgz
|
201
LICENSE
Normal file
201
LICENSE
Normal file
@ -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.
|
30
Makefile
Normal file
30
Makefile
Normal file
@ -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
|
93
README.md
Normal file
93
README.md
Normal file
@ -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
|
||||
```
|
||||
<!-- https://mostsecure.pw/ -->
|
||||
|
||||
### 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)
|
23
TODO
Normal file
23
TODO
Normal file
@ -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.
|
5
berth/Chart.yaml
Normal file
5
berth/Chart.yaml
Normal file
@ -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
|
1
berth/requirements.yaml
Normal file
1
berth/requirements.yaml
Normal file
@ -0,0 +1 @@
|
||||
dependencies: []
|
261
berth/templates/bin/_startvm.txt
Executable file
261
berth/templates/bin/_startvm.txt
Executable file
@ -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
|
132
berth/templates/deployment.yaml
Normal file
132
berth/templates/deployment.yaml
Normal file
@ -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
|
18
berth/values.yaml
Normal file
18
berth/values.yaml
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user