First cut of swap image and example

Signed-off-by: Avi Deitcher <avi@deitcher.net>

Fix spaces after commas

Remove MAINTAINER

Signed-off-by: Avi Deitcher <avi@deitcher.net>

Simplify swap.yml example to remove files section

Signed-off-by: Avi Deitcher <avi@deitcher.net>

Switch swap.sh to sh from bash and remove bash from image

Signed-off-by: Avi Deitcher <avi@deitcher.net>

Replace fallocate with dd and update calculation function to support it

Signed-off-by: Avi Deitcher <avi@deitcher.net>

Fix indentation

Signed-off-by: Avi Deitcher <avi@deitcher.net>

Change link to swap to just swap.sh

Signed-off-by: Avi Deitcher <avi@deitcher.net>

Fix indent

Signed-off-by: Avi Deitcher <avi@deitcher.net>
This commit is contained in:
Avi Deitcher
2017-04-26 09:40:04 +03:00
parent 60372d3750
commit 715cfbd02c
5 changed files with 346 additions and 0 deletions

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