Docker
Add a restart policy to a container that was already created
docker update --restart=always <container>
Change data directory
/etc/docker/daemon.json
{ "data-root": "/mnt/docker" }
Sort docker image by size
docker images --format "{{.ID}}\t{{.Size}}\t{{.Repository}}" | sort -k 2 -h
Get memory, cpu usage
docker stats --no-stream
Get image layer sizes
docker history --no-trunc <image>
For an alternative, see dive
Clean and check disk size usage
docker system df -v
# usually this solve everything (as long as you do not use `-v`, it does not delete the volumes)
docker system prune -a
Docker compose
Template
version: '3.3'
services:
vaultwarden:
image: vaultwarden/server:xxx
restart: unless-stopped
logging:
options:
max-size: 10m
volumes:
- vaultwarden_data:/data/
networks:
default:
ipv4_address: 172.1.x.2
env_file: .env
environment:
- SIGNUPS_ALLOWED=false
deploy:
resources:
limits:
cpus: 2
memory: 300M
labels:
- "io.parmentier.check_outdated_tag=true"
volumes:
vaultwarden_data:
networks:
default:
driver: bridge
ipam:
config:
- subnet: 172.1.x.0/24
Notes:
- ensure that an image has specific tag (if possible), avoid breaking a redeployment
- ensure you give resources limitation (memory/cpu)
- ensure you have a dedicated private network
- ensure it will restart during a restart/update through
unless-stopped
- ensure you create dedicated and permanent
volumes
- encourage environment variable in
.env
(great if there are a lot, avoid polluting docker-compose) - concerning
deploy
, on latest os/docker version, you might require to put cpus in float/string like:cpus: '2.'
equivalent to 2 cpu
Important notice: run docker-compose up
, AND NOT docker-compose create && docker-compose start
that will not create the network. Dont create the network yourself, it will forget options and make trouble to attach static ips.
CAREFUL: Delete containers and volumes
docker-compose down -v
Note: CAREFUL -v
will delete the volumes
Warning concerning deploy having not swarm
Still want to limit resources (memory, cpu), but it is not taken in consideration due to swarm absence ? just use --compatibility
docker-compose --compatibility ...
Check if update exists (minor or patch version)
#!/bin/bash
# REQUIRE: awk, sed, curl
# directory containing different projects and docker-compose.yml files
LOOKING_DIRECTORY="/home/projects"
REQUIRED_LABEL="tld.domain.check_outdated_tag=true"
# NOTE it is possible to use `yq` but it requires to install a python package (not managed by package manager) and it showed to be slowest than this
# https://stackoverflow.com/questions/5014632/how-can-i-parse-a-yaml-file-from-a-linux-shell-script
# https://github.com/mrbaseman/parse_yaml
function parse_yaml {
local prefix=$2
local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034')
sed -ne "s|,$s\]$s\$|]|" \
-e ":1;s|^\($s\)\($w\)$s:$s\[$s\(.*\)$s,$s\(.*\)$s\]|\1\2: [\3]\n\1 - \4|;t1" \
-e "s|^\($s\)\($w\)$s:$s\[$s\(.*\)$s\]|\1\2:\n\1 - \3|;p" $1 | \
sed -ne "s|,$s}$s\$|}|" \
-e ":1;s|^\($s\)-$s{$s\(.*\)$s,$s\($w\)$s:$s\(.*\)$s}|\1- {\2}\n\1 \3: \4|;t1" \
-e "s|^\($s\)-$s{$s\(.*\)$s}|\1-\n\1 \2|;p" | \
sed -ne "s|^\($s\):|\1|" \
-e "s|^\($s\)-$s[\"']\(.*\)[\"']$s\$|\1$fs$fs\2|p" \
-e "s|^\($s\)-$s\(.*\)$s\$|\1$fs$fs\2|p" \
-e "s|^\($s\)\($w\)$s:$s[\"']\(.*\)[\"']$s\$|\1$fs\2$fs\3|p" \
-e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" | \
awk -F$fs '{
indent = length($1)/2;
vname[indent] = $2;
for (i in vname) {if (i > indent) {delete vname[i]; idx[i]=0}}
if(length($2)== 0){ vname[indent]= ++idx[indent] };
if (length($3) > 0) {
vn=""; for (i=0; i<indent; i++) { vn=(vn)(vname[i])("_")}
printf("%s%s%s=\"%s\"\n", "'$prefix'",vn, vname[indent], $3);
}
}'
}
function check_new_img() {
local img="$1"
local complete_tested_version="$2"
local compose_file="$3"
local email_file="$4"
echo "[${img}] check if image ${complete_tested_version} exists"
if docker manifest inspect ${complete_tested_version} >/dev/null 2>&1; then
echo " -> new tag exists"
echo " - (${compose_file} - ${img}), new tag with version ${complete_tested_version} exists" >>${email_file}
true
return
fi
false
}
email_file=$(mktemp)
echo "Subject: outdated images" >${email_file}
echo "" >>${email_file}
for compose_file in $(find ${LOOKING_DIRECTORY} -name *-compose.yml); do
echo "Checking ${compose_file}"
# if you want to use `yq`, you will need something like:
# for img in $(yq -r 'try .services[] | select(.labels[] | contains("tld.domain.check_outdated_tag=true")) | .image' ${compose_file}); do
services_variables=$(parse_yaml "${compose_file}")
for service_name in $(echo "${services_variables}" | grep services | cut -d_ -f2 | uniq); do
if ! echo "${services_variables}" | grep services_${service_name}_labels | grep ${REQUIRED_LABEL} >/dev/null; then
continue
fi
img=$(echo "${services_variables}" | grep services_${service_name}_image | cut -d= -f2 | tr -d '"')
echo "[${img}] found label ${REQUIRED_LABEL}"
if ! echo ${img} | grep -E "[[:digit:]]+\.[[:digit:]]+\.?[[:digit:]]*" >/dev/null; then
echo "incapable to examine the image: ${img}"
continue
fi
# consider a version formated as described in https://semver.org/
version=$(echo ${img} | cut -d: -f2 | sed -nre 's/^[^0-9]*(([0-9]+\.)*[0-9]+).*/\1/p') # NOTE https://superuser.com/questions/363865/how-to-extract-a-version-number-using-sed
major_version=$(echo ${version} | cut -d. -f1)
minor_version=$(echo ${version} | cut -d. -f2)
patch_version=$(echo ${version} | cut -d. -f3)
if [ -z "${patch_version}" ]; then
complete_tested_version=$(echo ${img} | sed "s/${version}/${major_version}.$((minor_version+1))/")
check_new_img "${img}" "${complete_tested_version}" "${compose_file}" "${email_file}"
else
complete_tested_version=$(echo ${img} | sed "s/${version}/${major_version}.${minor_version}.$((patch_version+1))/")
check_new_img "${img}" "${complete_tested_version}" "${compose_file}" "${email_file}"
img_exists=$?
if [ "${img_exists}" != "0" ]; then
complete_tested_version=$(echo ${img} | sed "s/${version}/${major_version}.$((minor_version+1)).0/")
check_new_img "${img}" "${complete_tested_version}" "${compose_file}" "${email_file}"
img_exists=$?
if [ "${img_exists}" != "0" ]; then
complete_tested_version=$(echo ${img} | sed "s/${version}/${major_version}.$((minor_version+1))/")
check_new_img "${img}" "${complete_tested_version}" "${compose_file}" "${email_file}"
fi
fi
fi
done
done
lines_in_email_file=$(wc -l ${email_file} | awk '{print $1}')
if [ "${lines_in_email_file}" != "0" ]; then
curl --fail --silent --url 'smtps://smtp.gmail.com:465' --ssl-reqd --mail-from 'user@gmail.com' --mail-rcpt 'rcp@domain.tld' --upload-file ${email_file} --user 'user@gmail.com:password'
fi
rm ${email_file}
See also:
- https://www.reddit.com/r/selfhosted/comments/swzvj3/how_do_you_manage_docker_images_updates/
- https://stackoverflow.com/questions/26423515/how-to-automatically-update-your-docker-containers-if-base-images-are-updated