Use persistent Docker images for development (#113)
continuous-integration/drone/push Build is passing Details

This PR adds support for building Docker images during development which can be re-used multiple times. This allows us to easily run `docker-compose up` and `docker-compose down` many times without having to reinstall packages from scratch every time.

Reviewed-on: #113
This commit is contained in:
Max Erenberg 2023-12-03 23:29:11 -05:00
parent 392ec153d0
commit 5332259731
15 changed files with 423 additions and 263 deletions

View File

@ -5,34 +5,34 @@ name: default
steps:
# use the step name to mock out the gethostname() call in our tests
- name: phosphoric-acid
image: python:3.9-bullseye
image: python:3.9-slim-bullseye
# unfortunately we have to do everything in one step because there's no
# way to share system packages between steps
commands:
# install dependencies
- apt update && apt install -y libkrb5-dev libpq-dev python3-dev libaugeas0
- apt update
- apt install --no-install-recommends -y gcc libkrb5-dev libaugeas0
- python3 -m venv venv
- . venv/bin/activate
- pip install -r dev-requirements.txt
- pip install -r requirements.txt
- venv/bin/pip install -r dev-requirements.txt -r requirements.txt
# lint
- flake8
# unit + integration tests
- .drone/phosphoric-acid-setup.sh
- bash -c ". .drone/phosphoric-acid-setup.sh && IMAGE__setup && CONTAINER__setup"
- pytest -v
services:
- name: auth1
image: debian:bullseye
image: debian:bullseye-slim
commands:
- .drone/auth1-setup.sh
- bash -c ". .drone/auth1-setup.sh && IMAGE__setup && CONTAINER__setup"
- sleep infinity
- name: coffee
image: debian:bullseye
image: debian:bullseye-slim
commands:
- .drone/coffee-setup.sh
- bash -c ". .drone/coffee-setup.sh && IMAGE__setup && CONTAINER__setup"
- sleep infinity
trigger:

View File

@ -4,102 +4,128 @@ set -ex
. .drone/common.sh
# set FQDN in /etc/hosts
add_fqdn_to_hosts $(get_ip_addr $(hostname)) auth1
if [ -n "$CI" ]; then
# I'm not sure why, but we also need to remove the hosts entry for the
# container's real hostname, otherwise slapd only looks for the principal
# ldap/<container hostname> (this is with the sasl-host option)
sed -E "/\\b$(hostname)\\b/d" /etc/hosts > /tmp/hosts
cat /tmp/hosts > /etc/hosts
rm /tmp/hosts
fi
apt install -y psmisc
# If we don't do this then OpenLDAP uses a lot of RAM
ulimit -n 1024
# LDAP
apt install -y --no-install-recommends slapd ldap-utils libnss-ldapd sudo-ldap
# `service slapd stop` doesn't seem to work
killall slapd || true
service nslcd stop || true
rm -rf /etc/ldap/slapd.d
rm /var/lib/ldap/*
cp .drone/slapd.conf /etc/ldap/slapd.conf
cp .drone/ldap.conf /etc/ldap/ldap.conf
cp /usr/share/doc/sudo-ldap/schema.OpenLDAP /etc/ldap/schema/sudo.schema
cp .drone/rfc2307bis.schema /etc/ldap/schema/
cp .drone/csc.schema /etc/ldap/schema/
chown -R openldap:openldap /etc/ldap/schema/ /var/lib/ldap/ /etc/ldap/
sleep 0.5 && service slapd start
grep -Eq '^map group member uniqueMember$' /etc/nslcd.conf || \
echo 'map group member uniqueMember' >> /etc/nslcd.conf
sed -E -i 's/^uri .*$/uri ldap:\/\/auth1.csclub.internal/' /etc/nslcd.conf
sed -E -i 's/^base .*$/base dc=csclub,dc=internal/' /etc/nslcd.conf
cp .drone/nsswitch.conf /etc/nsswitch.conf
service nslcd start
ldapadd -c -f .drone/data.ldif -Y EXTERNAL -H ldapi:///
if [ -z "$CI" ]; then
ldapadd -c -f .drone/uwldap_data.ldif -Y EXTERNAL -H ldapi:/// || true
# setup ldapvi for convenience
apt install -y vim ldapvi
echo 'export EDITOR=vim' >> /root/.bashrc
echo 'alias ldapvi="ldapvi -Y EXTERNAL -h ldapi:///"' >> /root/.bashrc
fi
CONTAINER__fix_hosts() {
add_fqdn_to_hosts $(get_ip_addr $(hostname)) auth1
if [ -n "$CI" ]; then
# I'm not sure why, but we also need to remove the hosts entry for the
# container's real hostname, otherwise slapd only looks for the principal
# ldap/<container hostname> (this is with the sasl-host option)
sed -E "/\\b$(hostname)\\b/d" /etc/hosts > /tmp/hosts
cat /tmp/hosts > /etc/hosts
rm /tmp/hosts
fi
}
# KERBEROS
apt install -y krb5-admin-server krb5-user libpam-krb5 libsasl2-modules-gssapi-mit sasl2-bin
service krb5-admin-server stop || true
service krb5-kdc stop || true
service saslauthd stop || true
cp .drone/krb5.conf /etc/krb5.conf
cp .drone/kdc.conf /etc/krb5kdc.conf
echo '*/admin *' > /etc/krb5kdc/kadm5.acl
rm -f /var/lib/krb5kdc/*
echo -e 'krb5\nkrb5' | krb5_newrealm
service krb5-kdc start
service krb5-admin-server start
rm -f /etc/krb5.keytab
cat <<EOF | kadmin.local
IMAGE__setup_ldap() {
# In the "slim" Docker images, /usr/share/doc/* is excluded by default
echo 'path-include /usr/share/doc/sudo-ldap/schema.OpenLDAP' > /etc/dpkg/dpkg.cfg.d/zz-ceo
apt install -y --no-install-recommends slapd ldap-utils libnss-ldapd sudo-ldap
# `service slapd stop` doesn't seem to work
killall slapd || true
service nslcd stop || true
rm -rf /etc/ldap/slapd.d
rm /var/lib/ldap/*
cp .drone/slapd.conf /etc/ldap/slapd.conf
cp .drone/ldap.conf /etc/ldap/ldap.conf
cp /usr/share/doc/sudo-ldap/schema.OpenLDAP /etc/ldap/schema/sudo.schema
cp .drone/rfc2307bis.schema /etc/ldap/schema/
cp .drone/csc.schema /etc/ldap/schema/
chown -R openldap:openldap /etc/ldap/schema/ /var/lib/ldap/ /etc/ldap/
sleep 0.5 && service slapd start
ldapadd -c -f .drone/data.ldif -Y EXTERNAL -H ldapi:///
if [ -z "$CI" ]; then
ldapadd -c -f .drone/uwldap_data.ldif -Y EXTERNAL -H ldapi:/// || true
# setup ldapvi for convenience
apt install -y --no-install-recommends vim ldapvi
grep -q 'export EDITOR' /root/.bashrc || \
echo 'export EDITOR=vim' >> /root/.bashrc
grep -q 'alias ldapvi' /root/.bashrc || \
echo 'alias ldapvi="ldapvi -Y EXTERNAL -h ldapi:///"' >> /root/.bashrc
fi
}
IMAGE__setup_krb5() {
apt install -y krb5-admin-server krb5-user libpam-krb5 libsasl2-modules-gssapi-mit sasl2-bin
service krb5-admin-server stop || true
service krb5-kdc stop || true
service saslauthd stop || true
cp .drone/krb5.conf /etc/krb5.conf
cp .drone/kdc.conf /etc/krb5kdc.conf
echo '*/admin *' > /etc/krb5kdc/kadm5.acl
rm -f /var/lib/krb5kdc/*
echo -e 'krb5\nkrb5' | krb5_newrealm
service krb5-kdc start
service krb5-admin-server start
rm -f /etc/krb5.keytab
cat <<EOF | kadmin.local
addpol -minlength 4 default
addprinc -pw krb5 sysadmin/admin
addprinc -pw krb5 ctdalek
addprinc -pw krb5 exec1
addprinc -pw krb5 regular1
addprinc -pw krb5 office1
addprinc -randkey ceod/admin
addprinc -randkey host/auth1.csclub.internal
addprinc -randkey ldap/auth1.csclub.internal
ktadd host/auth1.csclub.internal
ktadd ldap/auth1.csclub.internal
EOF
groupadd keytab || true
chgrp keytab /etc/krb5.keytab
chmod 640 /etc/krb5.keytab
usermod -a -G keytab openldap
usermod -a -G sasl openldap
cat <<EOF > /usr/lib/sasl2/slapd.conf
# Add all of the people defined in data.ldif
for princ in ctdalek exec1 regular1 office1; do
echo "addprinc -pw krb5 $princ" | kadmin.local
done
groupadd keytab || true
chgrp keytab /etc/krb5.keytab
chmod 640 /etc/krb5.keytab
usermod -a -G keytab openldap
usermod -a -G sasl openldap
cat <<EOF > /usr/lib/sasl2/slapd.conf
mech_list: plain login gssapi external
pwcheck_method: saslauthd
EOF
sed -E -i 's/^START=.*$/START=yes/' /etc/default/saslauthd
sed -E -i 's/^MECHANISMS=.*$/MECHANISMS="kerberos5"/' /etc/default/saslauthd
service saslauthd start
while true; do
killall slapd
sleep 1
if service slapd start; then
break
fi
done
sed -E -i 's/^START=.*$/START=yes/' /etc/default/saslauthd
sed -E -i 's/^MECHANISMS=.*$/MECHANISMS="kerberos5"/' /etc/default/saslauthd
}
# sync with phosphoric-acid
nc -l 0.0.0.0 9000 &
if [ -z "$CI" ]; then
# sync with coffee
nc -l 0.0.0.0 9001 &
# sync with mail
nc -l 0.0.0.0 9002 &
fi
IMAGE__setup() {
# slapd needs /etc/hosts to be setup properly
CONTAINER__fix_resolv_conf
CONTAINER__fix_hosts
apt update
# for the 'killall' command
apt install -y psmisc
IMAGE__setup_ldap
IMAGE__setup_krb5
IMAGE__common_setup
service slapd stop || true
killall slapd || true
service krb5-admin-server stop || true
service krb5-kdc stop || true
service saslauthd stop || true
}
CONTAINER__setup() {
CONTAINER__fix_resolv_conf
CONTAINER__fix_hosts
local started_slapd=false
for i in {1..5}; do
if service slapd start; then
started_slapd=true
break
fi
sleep 1
done
if [ $started_slapd != "true" ]; then
echo "Failed to start slapd" >&2
return 1
fi
service krb5-admin-server start
service krb5-kdc start
service saslauthd start
service nslcd start
# Let other containers know that we're ready
nc -l -k 0.0.0.0 9000 &
}

View File

@ -4,25 +4,28 @@ set -ex
. .drone/common.sh
# set FQDN in /etc/hosts
add_fqdn_to_hosts $(get_ip_addr $(hostname)) coffee
add_fqdn_to_hosts $(get_ip_addr auth1) auth1
CONTAINER__fix_hosts() {
add_fqdn_to_hosts $(get_ip_addr $(hostname)) coffee
add_fqdn_to_hosts $(get_ip_addr auth1) auth1
}
apt install --no-install-recommends -y default-mysql-server postgresql
IMAGE__setup() {
IMAGE__ceod_setup
apt install --no-install-recommends -y default-mysql-server postgresql
# MYSQL
service mariadb stop
sed -E -i 's/^(bind-address[[:space:]]+= 127\.0\.0\.1)$/#\1/' /etc/mysql/mariadb.conf.d/50-server.cnf
service mariadb start
cat <<EOF | mysql
# MYSQL
service mariadb stop
sed -E -i 's/^(bind-address[[:space:]]+= 127\.0\.0\.1)$/#\1/' /etc/mysql/mariadb.conf.d/50-server.cnf
service mariadb start
cat <<EOF | mysql
CREATE USER IF NOT EXISTS 'mysql' IDENTIFIED BY 'mysql';
GRANT ALL PRIVILEGES ON *.* TO 'mysql' WITH GRANT OPTION;
EOF
# POSTGRESQL
service postgresql stop
POSTGRES_DIR=/etc/postgresql/*/main
cat <<EOF > $POSTGRES_DIR/pg_hba.conf
# POSTGRESQL
service postgresql stop
local POSTGRES_DIR=/etc/postgresql/*/main
cat <<EOF > $POSTGRES_DIR/pg_hba.conf
# TYPE DATABASE USER ADDRESS METHOD
local all postgres peer
host all postgres localhost md5
@ -36,19 +39,29 @@ local sameuser all peer
host sameuser all 0.0.0.0/0 md5
host sameuser all ::/0 md5
EOF
grep -Eq "^listen_addresses = '*'$" $POSTGRES_DIR/postgresql.conf || \
echo "listen_addresses = '*'" >> $POSTGRES_DIR/postgresql.conf
service postgresql start
su -c "
cat <<EOF | psql
grep -Eq "^listen_addresses = '*'$" $POSTGRES_DIR/postgresql.conf || \
echo "listen_addresses = '*'" >> $POSTGRES_DIR/postgresql.conf
service postgresql start
su -c "
cat <<EOF | psql
ALTER USER postgres WITH PASSWORD 'postgres';
REVOKE ALL ON SCHEMA public FROM public;
GRANT ALL ON SCHEMA public TO postgres;
EOF" postgres
if [ -z "$CI" ]; then
auth_setup coffee
fi
service mariadb stop || true
service postgresql stop || true
}
# sync with phosphoric-acid
nc -l 0.0.0.0 9000 &
CONTAINER__setup() {
CONTAINER__fix_resolv_conf
CONTAINER__fix_hosts
CONTAINER__ceod_setup
if [ -z "$CI" ]; then
CONTAINER__auth_setup coffee
fi
service mariadb start
service postgresql start
# sync with phosphoric-acid
nc -l -k 0.0.0.0 9000 &
}

View File

@ -1,77 +1,10 @@
# TODO: fix Drone
chmod 1777 /tmp
# don't resolve container names to *real* CSC machines
sed -E 's/([[:alnum:]-]+\.)*uwaterloo\.ca//g' /etc/resolv.conf > /tmp/resolv.conf
# remove empty 'search' lines, if we created them
sed -E -i '/^search[[:space:]]*$/d' /tmp/resolv.conf
# also remove the 'rotate' option, since this can cause the Docker DNS server
# to be circumvented
sed -E -i '/^options.*\brotate/d' /tmp/resolv.conf
cp /tmp/resolv.conf /etc/resolv.conf
rm /tmp/resolv.conf
# normally systemd creates /run/ceod for us
mkdir -p /run/ceod
# mock out systemctl
ln -sf /bin/true /usr/local/bin/systemctl
# mock out acme.sh
mkdir -p /root/.acme.sh
ln -sf /bin/true /root/.acme.sh/acme.sh
# mock out kubectl
cp .drone/mock_kubectl /usr/local/bin/kubectl
chmod +x /usr/local/bin/kubectl
# add k8s authority certificate
mkdir -p /etc/csc
cp .drone/k8s-authority.crt /etc/csc/k8s-authority.crt
# openssl is actually already present in the python Docker image,
# so we don't need to mock it out
# netcat is used for synchronization between the containers
export DEBIAN_FRONTEND=noninteractive
apt update
apt install -y netcat-openbsd
if [ "$(hostname)" != auth1 ]; then
# ceod uses Augeas, which is not installed by default in the Python
# Docker container
apt install -y libaugeas0
fi
get_ip_addr() {
getent hosts $1 | cut -d' ' -f1
}
add_fqdn_to_hosts() {
ip_addr=$1
hostname=$2
sed -E "/${ip_addr}.*\\b${hostname}\\b/d" /etc/hosts > /tmp/hosts
cp /tmp/hosts /etc/hosts
rm /tmp/hosts
echo "$ip_addr $hostname.csclub.internal $hostname" >> /etc/hosts
}
sync_with() {
host=$1
port=9000
if [ $# -eq 2 ]; then
port=$2
fi
synced=false
# give it 20 minutes (can be slow if you're using e.g. NFS or Ceph)
for i in {1..240}; do
if nc -vz $host $port ; then
synced=true
break
fi
sleep 5
done
test $synced = true
}
auth_setup() {
hostname=$1
# The IMAGE__ functions should be called when building the image.
# The CONTAINER__ functions should be called when running an instance of the
# image in a container.
IMAGE__auth_setup() {
# LDAP
apt install -y --no-install-recommends libnss-ldapd
service nslcd stop || true
@ -86,28 +19,98 @@ auth_setup() {
# KERBEROS
apt install -y krb5-user libpam-krb5 libsasl2-modules-gssapi-mit
cp .drone/krb5.conf /etc/krb5.conf
}
if [ $hostname = phosphoric-acid ]; then
sync_port=9000
elif [ $hostname = coffee ]; then
sync_port=9001
else
sync_port=9002
fi
sync_with auth1 $sync_port
IMAGE__common_setup() {
apt update
# netcat is used for synchronization between the containers
apt install -y netcat-openbsd
IMAGE__auth_setup
}
IMAGE__ceod_setup() {
IMAGE__common_setup
# ceod uses Augeas, which is not installed by default in the Python
# Docker container
apt install -y libaugeas0
}
CONTAINER__fix_resolv_conf() {
# don't resolve container names to *real* CSC machines
sed -E 's/([[:alnum:]-]+\.)*uwaterloo\.ca//g' /etc/resolv.conf > /tmp/resolv.conf
# remove empty 'search' lines, if we created them
sed -E -i '/^search[[:space:]]*$/d' /tmp/resolv.conf
# also remove the 'rotate' option, since this can cause the Docker DNS server
# to be circumvented
sed -E -i '/^options.*\brotate/d' /tmp/resolv.conf
# we can't replace /etc/resolv.conf using 'mv' because it's mounted into the container
cp /tmp/resolv.conf /etc/resolv.conf
rm /tmp/resolv.conf
}
CONTAINER__auth_setup() {
local hostname=$1
sync_with auth1
service nslcd start
rm -f /etc/krb5.keytab
cat <<EOF | kadmin -p sysadmin/admin -w krb5
addprinc -randkey host/$hostname.csclub.internal
ktadd host/$hostname.csclub.internal
addprinc -randkey ceod/$hostname.csclub.internal
ktadd host/$hostname.csclub.internal
ktadd ceod/$hostname.csclub.internal
EOF
if [ $hostname = phosphoric-acid ]; then
cat <<EOF | kadmin -p sysadmin/admin -w krb5
addprinc -randkey ceod/admin
ktadd ceod/admin
EOF
fi
service nslcd start
}
CONTAINER__ceod_setup() {
# normally systemd creates /run/ceod for us
mkdir -p /run/ceod
# mock out systemctl
ln -sf /bin/true /usr/local/bin/systemctl
# mock out acme.sh
mkdir -p /root/.acme.sh
ln -sf /bin/true /root/.acme.sh/acme.sh
# mock out kubectl
cp .drone/mock_kubectl /usr/local/bin/kubectl
chmod +x /usr/local/bin/kubectl
# add k8s authority certificate
mkdir -p /etc/csc
cp .drone/k8s-authority.crt /etc/csc/k8s-authority.crt
# openssl is actually already present in the python Docker image,
# so we don't need to mock it out
}
# Common utility functions
get_ip_addr() {
# There appears to be a bug in newer versions of Podman where using both
# --name and --hostname causes a container to have two identical DNS
# entries, which causes `getent hosts` to print two lines.
# So we use `head -n 1` to select just the first line.
getent hosts $1 | head -n 1 | cut -d' ' -f1
}
add_fqdn_to_hosts() {
local ip_addr=$1
local hostname=$2
sed -E "/${ip_addr}.*\\b${hostname}\\b/d" /etc/hosts > /tmp/hosts
# we can't replace /etc/hosts using 'mv' because it's mounted into the container
cp /tmp/hosts /etc/hosts
rm /tmp/hosts
echo "$ip_addr $hostname.csclub.internal $hostname" >> /etc/hosts
}
sync_with() {
local host=$1
local port=9000
local synced=false
# give it 20 minutes (can be slow if you're using e.g. NFS or Ceph)
for i in {1..240}; do
if nc -vz $host $port ; then
synced=true
break
fi
sleep 5
done
test $synced = true
}

View File

@ -4,20 +4,27 @@ set -ex
. .drone/common.sh
# set FQDN in /etc/hosts
add_fqdn_to_hosts $(get_ip_addr $(hostname)) mail
add_fqdn_to_hosts $(get_ip_addr auth1) auth1
CONTAINER__fix_hosts() {
add_fqdn_to_hosts $(get_ip_addr $(hostname)) mail
add_fqdn_to_hosts $(get_ip_addr auth1) auth1
}
. venv/bin/activate
python -m tests.MockMailmanServer &
python -m tests.MockSMTPServer &
python -m tests.MockCloudStackServer &
python -m tests.MockHarborServer &
IMAGE__setup() {
IMAGE__ceod_setup
}
auth_setup mail
# for the VHostManager
mkdir -p /run/ceod/member-vhosts
# sync with phosphoric-acid
nc -l 0.0.0.0 9000 &
CONTAINER__setup() {
CONTAINER__fix_resolv_conf
CONTAINER__fix_hosts
CONTAINER__ceod_setup
CONTAINER__auth_setup mail
# for the VHostManager
mkdir -p /run/ceod/member-vhosts
# mock services
venv/bin/python -m tests.MockMailmanServer &
venv/bin/python -m tests.MockSMTPServer &
venv/bin/python -m tests.MockCloudStackServer &
venv/bin/python -m tests.MockHarborServer &
# sync with phosphoric-acid
nc -l -k 0.0.0.0 9000 &
}

View File

@ -4,29 +4,44 @@ set -ex
. .drone/common.sh
# set FQDN in /etc/hosts
add_fqdn_to_hosts "$(get_ip_addr $(hostname))" phosphoric-acid
add_fqdn_to_hosts "$(get_ip_addr auth1)" auth1
add_fqdn_to_hosts "$(get_ip_addr coffee)" coffee
# mail container doesn't run in CI
if [ -z "$CI" ]; then
add_fqdn_to_hosts $(get_ip_addr mail) mail
fi
CONTAINER__fix_hosts() {
add_fqdn_to_hosts "$(get_ip_addr $(hostname))" phosphoric-acid
add_fqdn_to_hosts "$(get_ip_addr auth1)" auth1
add_fqdn_to_hosts "$(get_ip_addr coffee)" coffee
# mail container doesn't run in CI
if [ -z "$CI" ]; then
add_fqdn_to_hosts $(get_ip_addr mail) mail
fi
}
auth_setup phosphoric-acid
CONTAINER__setup_userdirs() {
# initialize the skel directory
shopt -s dotglob
mkdir -p /users/skel
cp /etc/skel/* /users/skel/
# initialize the skel directory
shopt -s dotglob
mkdir -p /users/skel
cp /etc/skel/* /users/skel/
# create directories for users
for user in ctdalek regular1 exec1; do
mkdir -p /users/$user
chown $user:$user /users/$user
done
}
# create directories for users
for user in ctdalek regular1 exec1; do
mkdir -p /users/$user
chown $user:$user /users/$user
done
IMAGE__setup() {
IMAGE__ceod_setup
# git is required by the ClubWebHostingService
apt install --no-install-recommends -y git
}
sync_with coffee
if [ -z "$CI" ]; then
sync_with mail
fi
CONTAINER__setup() {
CONTAINER__fix_resolv_conf
CONTAINER__fix_hosts
CONTAINER__ceod_setup
CONTAINER__auth_setup phosphoric-acid
CONTAINER__setup_userdirs
echo "ktadd ceod/admin" | kadmin -p sysadmin/admin -w krb5
sync_with coffee
if [ -z "$CI" ]; then
sync_with mail
fi
}

View File

@ -1,5 +1,5 @@
#!/bin/bash
docker run --rm -v "$PWD:$PWD:z" -w "$PWD" python:3.9-bullseye sh -c './lint-docker.sh'
docker run --rm -v "$PWD:$PWD:z" -w "$PWD" python:3.9-bullseye scripts/lint-docker.sh
exit $?

View File

@ -10,17 +10,29 @@ overview of its architecture.
The API documentation is available as a plain HTML file in [docs/redoc-static.html](docs/redoc-static.html).
## Development
### Docker
### Podman
If you are not modifying code related to email or Mailman, then you may use
Docker containers instead, which are much easier to work with than the VM.
Podman containers instead, which are much easier to work with than the VM.
First, make sure you create the virtualenv:
If you are using Podman, make sure to set the `DOCKER_HOST` environment variable
if you have not done so already:
```bash
# Add the following to e.g. your ~/.bashrc
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock
```
The Podman socket also needs to be running:
```bash
# Enabled by default on Debian, but not on Fedora
systemctl --user enable --now podman.socket
```
First, create the container images:
```sh
docker run --rm -v "$PWD:$PWD:z" -w "$PWD" python:3.9-bullseye sh -c 'apt update && apt install -y libaugeas0 && python -m venv venv && . venv/bin/activate && pip install -r requirements.txt -r dev-requirements.txt'
scripts/build-all-images.sh
```
Then bring up the containers:
```sh
docker-compose up -d # or without -d to run in the foreground
docker-compose up -d
```
This will create some containers with the bare minimum necessary for ceod to
run, and start ceod on each of phosphoric-acid, mail, and coffee container.
@ -188,7 +200,7 @@ flask run -h 0.0.0.0 -p 9987
```
Sometimes changes you make in the source code don't show up while Flask
is running. Stop the flask app (Ctrl-C), run `clear_cache.sh`, then
is running. Stop the flask app (Ctrl-C), run `scripts/clear_cache.sh`, then
restart the app.
## Interacting with the application

View File

@ -1,41 +1,51 @@
version: "3.6"
x-common: &common
image: python:3.9-bullseye
image: ceo-generic:bullseye
volumes:
- .:$PWD:z
- ceo-venv:/app/venv:ro
- ./.drone:/app/.drone:ro
- ./docker-entrypoint.sh:/app/docker-entrypoint.sh:ro
- ./ceo:/app/ceo:ro
- ./ceo_common:/app/ceo_common:ro
- ./ceod:/app/ceod:ro
- ./tests:/app/tests:ro
security_opt:
- label:disable
working_dir: /app
entrypoint:
- ./docker-entrypoint.sh
x-ceod-common: &ceod-common
<<: *common
environment:
FLASK_APP: ceod.api
FLASK_DEBUG: "true"
working_dir: $PWD
entrypoint:
- ./docker-entrypoint.sh
services:
auth1:
<<: *common
image: debian:bullseye
image: ceo-auth1:bullseye
hostname: auth1
command: auth1
coffee:
<<: *common
<<: *ceod-common
image: ceo-coffee:bullseye
command: coffee
hostname: coffee
depends_on:
- auth1
mail:
<<: *common
<<: *ceod-common
command: mail
hostname: mail
depends_on:
- auth1
phosphoric-acid:
<<: *common
<<: *ceod-common
command: phosphoric-acid
hostname: phosphoric-acid
depends_on:
@ -43,4 +53,8 @@ services:
- coffee
- mail
volumes:
ceo-venv:
external: true
# vim: expandtab sw=2 ts=2

View File

@ -1,16 +1,21 @@
#!/bin/sh -e
#!/bin/bash
if ! [ -d venv ]; then
echo "You need to create the virtualenv first!" >&2
set -ex
if [ $# -ne 1 ]; then
echo "Usage: $0 <host>" >&2
exit 1
fi
host="$1"
[ -x ".drone/$host-setup.sh" ] && ".drone/$host-setup.sh"
if ! [ -d venv ]; then
echo "You need to mount the virtualenv" >&2
exit 1
fi
. .drone/$host-setup.sh
CONTAINER__setup
if [ "$host" = auth1 ]; then
exec sleep infinity
else
. venv/bin/activate
exec .drone/supervise.sh flask run -h 0.0.0.0 -p 9987
exec .drone/supervise.sh venv/bin/flask run -h 0.0.0.0 -p 9987
fi

49
scripts/build-all-images.sh Executable file
View File

@ -0,0 +1,49 @@
#!/bin/bash
set -eux
SUITE=bullseye
PYTHON_VER=3.9
DOCKER=docker
if command -v podman >/dev/null; then
DOCKER=podman
export BUILDAH_FORMAT=docker
fi
build_image() {
local HOST=$1
local BASE_IMAGE=$2
local IMAGE=ceo-$HOST:$SUITE
if $DOCKER image exists $IMAGE; then
return
fi
run=". .drone/$HOST-setup.sh && IMAGE__setup"
if [ $HOST = generic ]; then
run=". .drone/phosphoric-acid-setup.sh && IMAGE__setup"
fi
$DOCKER build -t $IMAGE -f - . <<EOF
FROM $BASE_IMAGE
WORKDIR /app
COPY .drone .drone
RUN [ "/bin/bash", "-c", "$run" ]
ENTRYPOINT [ "./docker-entrypoint.sh" ]
EOF
}
# Install the Python dependencies into a volume and re-use it for all the containers
if ! $DOCKER volume exists ceo-venv; then
$DOCKER volume create ceo-venv
$DOCKER run \
--rm \
-w /app/venv \
-v ceo-venv:/app/venv:z \
-v ./requirements.txt:/tmp/requirements.txt:ro \
-v ./dev-requirements.txt:/tmp/dev-requirements.txt:ro \
python:$PYTHON_VER-slim-$SUITE \
sh -c "apt update && apt install --no-install-recommends -y gcc libkrb5-dev libaugeas0 && python -m venv . && bin/pip install -r /tmp/requirements.txt -r /tmp/dev-requirements.txt"
fi
build_image auth1 debian:$SUITE-slim
build_image coffee python:$PYTHON_VER-slim-$SUITE
# Used by the phosphoric-acid and mail containers
build_image generic python:$PYTHON_VER-slim-$SUITE

16
scripts/delete-all-images.sh Executable file
View File

@ -0,0 +1,16 @@
#!/bin/bash
set -eux
DOCKER=docker
if command -v podman >/dev/null; then
DOCKER=podman
fi
$DOCKER images --format="{{index .Names 0}}" | \
grep -E "^(localhost/)?ceo-" | \
while read name; do $DOCKER rmi $name; done
if $DOCKER volume exists ceo-venv; then
$DOCKER volume rm ceo-venv
fi