Initial commit.
This commit is contained in:
commit
76aebc9f9e
|
@ -0,0 +1,2 @@
|
||||||
|
helm.log
|
||||||
|
berth-0.1.0.tgz
|
|
@ -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.
|
|
@ -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
|
|
@ -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)
|
|
@ -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.
|
|
@ -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
|
|
@ -0,0 +1 @@
|
||||||
|
dependencies: []
|
|
@ -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
|
|
@ -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
|
|
@ -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…
Reference in New Issue