mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-07-19 09:16:29 +00:00
Merge pull request #1715 from deitch/swap-module
First cut of swap image and example
This commit is contained in:
commit
1cd201aac5
83
examples/swap.yml
Normal file
83
examples/swap.yml
Normal 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
13
pkg/swap/Dockerfile
Normal 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
30
pkg/swap/Makefile
Normal 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
85
pkg/swap/README.md
Normal 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
135
pkg/swap/swap.sh
Executable 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
|
Loading…
Reference in New Issue
Block a user