Merge pull request #1715 from deitch/swap-module

First cut of swap image and example
This commit is contained in:
Justin Cormack 2017-04-26 21:47:54 +01:00 committed by GitHub
commit 1cd201aac5
5 changed files with 346 additions and 0 deletions

83
examples/swap.yml Normal file
View File

@ -0,0 +1,83 @@
kernel:
image: "linuxkit/kernel:4.9.x"
cmdline: "console=ttyS0 console=tty0 page_poison=1"
init:
- linuxkit/init:42fe8cb1508b3afed39eb89821906e3cc7a70551
- linuxkit/runc:b0fb122e10dbb7e4e45115177a61a3f8d68c19a9
- linuxkit/containerd:60e2486a74c665ba4df57e561729aec20758daed
- linuxkit/ca-certificates:eabc5a6e59f05aa91529d80e9a595b85b046f935
onboot:
- name: sysctl
image: "linuxkit/sysctl:2cf2f9d5b4d314ba1bfc22b2fe931924af666d8c"
net: host
pid: host
ipc: host
capabilities:
- CAP_SYS_ADMIN
readonly: true
- name: binfmt
image: "linuxkit/binfmt:8881283ac627be1542811bd25c85e7782aebc692"
binds:
- /proc/sys/fs/binfmt_misc:/binfmt_misc
readonly: true
- name: dhcpcd
image: "linuxkit/dhcpcd:48e249ebef6a521eed886b3bce032db69fbb4afa"
binds:
- /var:/var
- /tmp/etc:/etc
capabilities:
- CAP_NET_ADMIN
- CAP_NET_BIND_SERVICE
- CAP_NET_RAW
net: host
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
- name: format
image: "linuxkit/format:53748000acf515549d398e6ae68545c26c0f3a2e"
binds:
- /dev:/dev
capabilities:
- CAP_SYS_ADMIN
- CAP_MKNOD
- name: mount
image: "linuxkit/mount:d2669e7c8ddda99fa0618a414d44261eba6e299a"
binds:
- /dev:/dev
- /var:/var:rshared,rbind
capabilities:
- CAP_SYS_ADMIN
rootfsPropagation: shared
command: ["/mount.sh", "/var/external"]
- name: swap
image: "linuxkit/swap:68deee354ec4bbed405c5efedb25d60bb799b07d"
net: host
pid: host
capabilities:
- CAP_SYS_ADMIN
readonly: true
binds:
- /var:/var
- /dev:/dev
command: ["swap.sh", "--path", "/var/external/swap", "--size","1G"]
services:
- name: rngd
image: "linuxkit/rngd:3dad6dd43270fa632ac031e99d1947f20b22eec9"
capabilities:
- CAP_SYS_ADMIN
oomScoreAdj: -800
readonly: true
- name: nginx
image: "nginx:alpine"
capabilities:
- CAP_NET_BIND_SERVICE
- CAP_CHOWN
- CAP_SETUID
- CAP_SETGID
- CAP_DAC_OVERRIDE
net: host
trust:
image:
- linuxkit/kernel
outputs:
- format: kernel+initrd
- format: iso-bios
- format: iso-efi

13
pkg/swap/Dockerfile Normal file
View File

@ -0,0 +1,13 @@
FROM alpine:3.5
# swap command - only minimal Alpine install
# use util-linux to get swapfile utils
# at some point, hopefully use our own mkswap and swapon
RUN apk add --update util-linux
# add the entrypoint and make it executable
COPY . ./
# ENTRYPOINT
ENTRYPOINT swap.sh

30
pkg/swap/Makefile Normal file
View File

@ -0,0 +1,30 @@
# copy from mount
.PHONY: tag push clean
BASE=alpine:3.5
IMAGE=linuxkit/swap
default: push
hash: Dockerfile swap.sh
DOCKER_CONTENT_TRUST=1 docker pull $(BASE)
tar cf - $^ | docker build --no-cache -t $(IMAGE):build -
docker run --rm --entrypoint /bin/sh $(IMAGE):build -c "cat $^ /lib/apk/db/installed | sha1sum" | sed 's/ .*//' > $@
push: hash
docker pull $(IMAGE):$(shell cat hash) || \
(docker tag $(IMAGE):build $(IMAGE):$(shell cat hash) && \
docker push $(IMAGE):$(shell cat hash))
docker rmi $(IMAGE):build
rm -f hash
tag: hash
docker pull $(IMAGE):$(shell cat hash) || \
docker tag $(IMAGE):build $(IMAGE):$(shell cat hash)
docker rmi $(IMAGE):build
rm -f hash
clean:
rm -f hash
.DELETE_ON_ERROR:

85
pkg/swap/README.md Normal file
View File

@ -0,0 +1,85 @@
# LinuxKit Swap
Image to enable creation of a swap file for a [linuxkit](https://github.com/linuxkit/linuxkit)-generated image.
## Usage
Normally, unless you are running explicitly in a desktop version, LinuxKit images do not have swap enabled. If you want swap, add the following to your `moby.yml`:
```
onboot:
- name: swap
image: "linuxkit/swap:1.0.0"
net: none
pid: host
capabilities:
- CAP_SYS_ADMIN
readonly: true
binds:
- /dev:/dev
- /var:/var
command: ["swap.sh","--path","/var/external/swap","--size","2G"]
```
Note that you **nust** mount the following:
* `/var` to `/var` so it can place the swapfile in the right location.
* `/dev` to `/dev` so it can do the right thing for devices
### Options
Options are passed to it via command-line options. The following are the options. Details follow.
|Option|Parameter|Default|Required|Notes|
|---|---|---|---|---|
|`--path`|Path to file as seen in the underlying OS||**Yes**||
|`--size`|Target swapfile size||**Yes**||
|`--condition`|_condition_||No|Condition that must be met to create a swapfile|
|`--debug`||No|Turns on verbose output from the command making the swap|
#### File
You can create a swapfile at the given path. You **must** provide exactly one swapfile path, or none will be created; there is no default. Passing fewer than or more than one `--path` option causes the container to exit with an error.
The option `--path` takes a single argument _path_, path to the swapfile, e.g. `/var/mnt/swap2`.
You **always** should put the swap file somewhere under `/var`, since that is where read-writable files and mounts exist in linuxkit images.
#### Size
`--size <size>` indicates the desired swapfile size, e.g. `2G` `100M` `5670K` `8765432`. There is no default. Acceptable size units are `G`, `M`, `K` and bytes of no unit provided.
If disk space on the requested partition is insufficient to create the swapfile, the container exits with an error.
#### Conditions
You may want to create a swapfile only if certain conditions are met. Supported conditions are:
* An external disk is available
* Partition on which the swapfile will sit is of a minimum size.
**All** conditions must be met. If a condition fails, the swapfile is not created, but the container exits with no error, unless you set the condition as `required`.
Conditions are structured as follows: _type_:_parameter_:_required_
In all cases, you may leave off _required_ if you wish to treat it as false, i.e. do not create swapfile but exit with no error if the condition is not met.
##### Partition exists
LinuxKit may be running from a small disk, and you only want to run if a particular large external disk is available. In that case, pass `--condition part:<path>:<required>` to indicate that swapfile is to be created only if _path_ already exists and is a mount point.
Example: `--condition part:/var/mnt/external`
##### Size
You may set a minimum size for a partition (likely the one on which the swapfile will be created) using the `size` condition of the format `--condition size:<path>:<size>:<required>` to indicate that swapfile is to be created only if the partition on which _path_ exists is of minimum size _size_. Acceptable sizes are identical to those for the swapfile.
Examples:
* `--condition partsize:/var/mnt/external:100G:true`
## Example
An example yml file is included in [examples/swap.yml](../../examples/swap.yml). `swap.yml`. Note that you need to attach an external disk - trying to create a swapfile in tmpfs `/var` will fail.
The sample command to run the enclosed is:
```
moby build swap.yml
moby run -disk-size 4096 swap
```

135
pkg/swap/swap.sh Executable file
View File

@ -0,0 +1,135 @@
#!/bin/sh
set -e
while [ $# -gt 1 ]; do
key="$1"
case $key in
--debug)
set -x
;;
--path)
path="$2"
shift # past argument
;;
--size)
size="$2"
shift # past argument
;;
--encrypt)
ENCRYPT=true
;;
--condition)
CONDITIONS="$CONDITIONS $2"
shift
;;
*)
echo "Unknown option passed to swapmaker: $key" # unknown option
exit 1
;;
esac
shift # past argument or value
done
function disksize_to_count {
local blocksize=$1
local origsize=$2
local ret
case $origsize in
*G)
ret=$(( ${origsize%%G} * 1024 * 1024 * 1024 ))
;;
*M)
ret=$(( ${origsize%%M} * 1024 * 1024 ))
;;
*K)
ret=$(( ${origsize%%K} * 1024 ))
;;
*)
ret=$origsize
;;
esac
ret=$(( $ret / $blocksize ))
echo $ret
}
## make sure path is valid
if [ -z "${path}" ]; then
echo "swap: --file <path> must be defined"
exit 1
fi
if [ "${path:0:5}" != "/var/" -o ${#path} -lt 6 ]; then
echo "--file <path> option must be under /var"
exit 1
fi
if [ -z "${size}" ]; then
echo "swap: --size <size> must be defined"
exit 1
fi
## check each of our conditions
for cond in $CONDITIONS; do
# split the condition parts
IFS=: read condtype arg1 arg2 arg3 arg4 <<< "$cond"
case $condtype in
part)
partition=$arg1
required=$arg2
# check that the path exists as its own mount point
set +e
grep -qs $partition /proc/mounts
is_mnt=$?
set -e
if [ $is_mnt -ne 0 ]; then
[ "$required" == "true" ] && exit 1
exit 0
fi
;;
partsize)
partition=$arg1
minsize=$arg2
required=$arg3
# check that the partition on which it exists has sufficient size
partsize=$(df -k $partition | tail -1 | awk '{print $2}')
partsize=$(( $partsize * 1024 ))
# convert minsize to bytes
minsize=$(disksize_to_count 1 $minsize)
if [ $partsize -lt $minsize ]; then
[ "$required" == "true" ] && exit 1
exit 0
fi
;;
*)
echo "Unknown condition: $cond"
exit 1
;;
esac
done
## if a condition failed:
### Required? exit 1
### Else? exit 0
## Allocate the file
dd if=/dev/zero of=$path bs=1024 count=$(disksize_to_count 1024 $size)
chmod 0600 $path
## was it encrypted? use cryptsetup and get the mapped device
if [ "$ENCRYPT" == "true" ]; then
# might need
#loop=$(losetup -f)
#losetup ${loop} ${path}
cryptsetup open --type plain --key-file /dev/urandom --key-size=256 --hash=sha256 --cipher=aes-cbc-essiv --offset=0 ${path} swapfile
SWAPDEV=/dev/mapper/swapfile
else
SWAPDEV=$path
fi
## mkswap and swapon the device
/sbin/mkswap $SWAPDEV
/sbin/swapon $SWAPDEV