From 147340c063e64a6e0f736d88ae5005172e7d3b48 Mon Sep 17 00:00:00 2001 From: "Bruno P. Kinoshita" Date: Sun, 6 Aug 2023 22:37:31 +0200 Subject: [PATCH] Add Docker image, Docker Compose example cluster, and README docs --- .gitignore | 4 + dockerfiles/Dockerfile | 180 +++++++++++++++++++++++++ dockerfiles/README.md | 234 +++++++++++++++++++++++++++++++++ dockerfiles/docker-compose.yml | 54 ++++++++ dockerfiles/test.sh | 112 ++++++++++++++++ 5 files changed, 584 insertions(+) create mode 100644 dockerfiles/Dockerfile create mode 100644 dockerfiles/README.md create mode 100644 dockerfiles/docker-compose.yml create mode 100755 dockerfiles/test.sh diff --git a/.gitignore b/.gitignore index eb86c7600..40e7cb3ec 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,7 @@ coverage/ /.coverage test/coverage.xml +# Docker +dockerfiles/id_rsa* +dockerfiles/authorized_keys + diff --git a/dockerfiles/Dockerfile b/dockerfiles/Dockerfile new file mode 100644 index 000000000..3de4a04a7 --- /dev/null +++ b/dockerfiles/Dockerfile @@ -0,0 +1,180 @@ +FROM mambaorg/micromamba:1.4.9-bullseye-slim AS micromamba + +# The micromamba image is referenced in a multi-stage build. +# Note that around 90% of the content of this image is actually +# for micromamba users, permissions, dependencies, and SSH. +# The Autosubmit portion is rather small, being mainly install +# Autosubmit with pip, and run `autosubmit configure` and then +# `autosubmit install`. It would be possible to create another +# image autosubmit-base, for example, with the users, permissions, +# dependencies, and SSH. Which would tremendously reduce this. + +FROM debian:bullseye-slim + +ARG AUTOSUBMIT_ROOT_DIR=/app/autosubmit/ + +USER root + +# micromamba docs, https://micromamba-docker.readthedocs.io/en/latest/advanced_usage.html#adding-micromamba-to-an-existing-docker-image + +# if your image defaults to a non-root user, then you may want to make the +# next 3 ARG commands match the values in your image. You can get the values +# by running: docker run --rm -it my/image id -a +ARG MAMBA_USER=mamba +ARG MAMBA_USER_ID=1000 +ARG MAMBA_USER_GID=1000 +ENV MAMBA_USER=$MAMBA_USER +ENV MAMBA_ROOT_PREFIX="/opt/conda" +ENV MAMBA_EXE="/bin/micromamba" + +COPY --from=micromamba "$MAMBA_EXE" "$MAMBA_EXE" +COPY --from=micromamba /usr/local/bin/_activate_current_env.sh /usr/local/bin/_activate_current_env.sh +COPY --from=micromamba /usr/local/bin/_dockerfile_shell.sh /usr/local/bin/_dockerfile_shell.sh +COPY --from=micromamba /usr/local/bin/_entrypoint.sh /usr/local/bin/_entrypoint.sh +COPY --from=micromamba /usr/local/bin/_dockerfile_initialize_user_accounts.sh /usr/local/bin/_dockerfile_initialize_user_accounts.sh +COPY --from=micromamba /usr/local/bin/_dockerfile_setup_root_prefix.sh /usr/local/bin/_dockerfile_setup_root_prefix.sh + +RUN /usr/local/bin/_dockerfile_initialize_user_accounts.sh && \ + /usr/local/bin/_dockerfile_setup_root_prefix.sh + +USER $MAMBA_USER + +SHELL ["/usr/local/bin/_dockerfile_shell.sh"] + +ENTRYPOINT ["/usr/local/bin/_entrypoint.sh"] +# Optional: if you want to customize the ENTRYPOINT and have a conda +# environment activated, then do this: +# ENTRYPOINT ["/usr/local/bin/_entrypoint.sh", "my_entrypoint_program"] + +# end micromamba + +# micromamba docs, https://micromamba-docker.readthedocs.io/en/latest/advanced_usage.html#changing-the-user-id-or-name + +ARG NEW_MAMBA_USER=autosubmit +ARG NEW_MAMBA_USER_ID=1000 +ARG NEW_MAMBA_USER_GID=1000 +USER root + +RUN if grep -q '^ID=alpine$' /etc/os-release; then \ + # alpine does not have usermod/groupmod + apk add --no-cache --virtual temp-packages shadow=4.13-r0; \ + fi && \ + usermod "--login=${NEW_MAMBA_USER}" "--home=/home/${NEW_MAMBA_USER}" \ + --move-home "-u ${NEW_MAMBA_USER_ID}" "${MAMBA_USER}" && \ + groupmod "--new-name=${NEW_MAMBA_USER}" \ + "-g ${NEW_MAMBA_USER_GID}" "${MAMBA_USER}" && \ + if grep -q '^ID=alpine$' /etc/os-release; then \ + # remove the packages that were only needed for usermod/groupmod + apk del temp-packages; \ + fi && \ + # Update the expected value of MAMBA_USER for the + # _entrypoint.sh consistency check. + echo "${NEW_MAMBA_USER}" > "/etc/arg_mamba_user" && \ + : +ENV MAMBA_USER=$NEW_MAMBA_USER +USER $MAMBA_USER + +# end micromamba + +WORKDIR "${AUTOSUBMIT_ROOT_DIR}" + +ENV ENV_NAME=base +ENV PATH "$MAMBA_ROOT_PREFIX/bin:/usr/bin:/usr/local/bin:$PATH" + +# The directories the container will use for Autosubmit files. +USER root +RUN mkdir -pv "${AUTOSUBMIT_ROOT_DIR}/logs" && \ + mkdir -pv "${AUTOSUBMIT_ROOT_DIR}/metadata" && \ + chown -R "${MAMBA_USER}:${MAMBA_USER}" "${AUTOSUBMIT_ROOT_DIR}" + +# update-ca-certificates is for: libmamba No CA certificates found on system. +# openssh-server is for: Autosubmit platforms. +# git is for: Autosubmit Git projects. +# bash, curl, dialog, graphviz, python3-tk, sqlite3 are for: Autosubmit dependencies listed at readthedocs. +# less, vim, iputils-ping, net-tools are for: convenience. +# TODO: add something like xpdf=3.04+git20210103-3 if GUI/X is needed. +RUN apt update && \ + apt install -y \ + bash=5.1-2+deb11u1 \ + ca-certificates=20210119 \ + curl=7.74.0-1.3+deb11u7 \ + desktop-file-utils=0.26-1 \ + dialog=1.3-20201126-1 \ + graphviz=2.42.2-5 \ + iputils-ping=3:20210202-1 \ + less=551-2 \ + net-tools=1.60+git20181103.0eebece-1 \ + openssh-server=1:8.4p1-5+deb11u1 \ + python3-tk=3.9.2-1 \ + sqlite3=3.34.1-3 \ + sudo=1.9.5p2-3+deb11u1 \ + vim=2:8.2.2434-3+deb11u1 \ + xdg-utils=1.1.3-4.1 && \ + update-ca-certificates && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +USER $MAMBA_USER + +# Install and configure Autosubmit. + +# Install Python. +RUN micromamba install --yes --name base --channel conda-forge \ + git=2.41.0 \ + python=3.9.16 && \ + micromamba clean --all --yes && \ + /usr/local/bin/_activate_current_env.sh + +# Install Autosubmit. +RUN pip install autosubmit==4.0.84 + +# Configure Autosubmit. +RUN autosubmit configure \ + -db "${AUTOSUBMIT_ROOT_DIR}/database/" \ + -dbf autosubmit.db \ + -lr "${AUTOSUBMIT_ROOT_DIR}/experiments/" && \ + autosubmit install + +# SSH (for Autosubmit local platform.) +USER root + +RUN chown -R "${MAMBA_USER}:${MAMBA_USER}" "/home/${MAMBA_USER}/" && \ + chmod 0755 "/home/${MAMBA_USER}/" && \ + mkdir -pv /var/run/sshd && \ + mkdir -pv "/home/$MAMBA_USER/.ssh" && \ + chmod 0700 "/home/$MAMBA_USER/.ssh" && \ + touch "/home/$MAMBA_USER/.ssh/authorized_keys" && \ + chmod 600 "/home/$MAMBA_USER/.ssh/authorized_keys" && \ + chown -R "${MAMBA_USER}:${MAMBA_USER}" "/home/$MAMBA_USER/.ssh" && \ + usermod -a -G sudo "${MAMBA_USER}" && \ + sed -i "s/^%sudo.*$/%sudo ALL=(ALL:ALL) NOPASSWD:ALL/g" /etc/sudoers && \ + sed -i 's/#\?\(PasswordAuthentication\s*\).*$/\1 no/g' /etc/ssh/sshd_config && \ + sed -i 's/#\?\(SyslogFacility.*\)$/\1/g' /etc/ssh/sshd_config && \ + sed -i 's/#\?\(LogLevel\).*$/\1 VERBOSE/g' /etc/ssh/sshd_config && \ + sed -i 's/#\?.*StrictHostKeyChecking.*$/StrictHostKeyChecking accept-new/g' /etc/ssh/ssh_config && \ + env | egrep -v "^(HOME=|USER=|MAIL=|LC_ALL=|LS_COLORS=|LANG=|HOSTNAME=|PWD=|TERM=|SHLVL=|LANGUAGE=|_=)" >> /etc/environment + +# TODO: For PDF and GUI/X support, we could use something similar to: +# +# COPY <22/tcp, :::32783->22/tcp +dockerfiles-computing_node-1 lscr.io/linuxserver/openssh-server:latest "/init" computing_node 33 minutes ago Up 32 minutes 2222/tcp, 0.0.0.0:32782->22/tcp, :::32782->22/tcp +dockerfiles-computing_node-2 lscr.io/linuxserver/openssh-server:latest "/init" computing_node 33 minutes ago Up 32 minutes 2222/tcp, 0.0.0.0:32781->22/tcp, :::32781->22/tcp +``` + +You can connect to the Autosubmit VM via Docker or SSH. The example below +uses Docker. Autosubmit will be loaded automatically via the Micromamba +Conda environment: + +```bash +# Docker Compose container names may change, use docker ps +# to confirm yours is called autosubmit. +$ docker exec -ti autosubmit /bin/bash +``` + +For SSH, you have to use the randomly generated local TCP port that +is bound to the port `22` inside the container. Looking at the example above, +you could use: + +```bash +$ ssh -i id_rsa -p 32791 autosubmit@localhost +Warning: Permanently added '[localhost]:32791' (ED25519) to the list of known hosts. +X11 forwarding request failed on channel 0 +Linux b35e552f22bc 5.15.0-78-generic #85-Ubuntu SMP Fri Jul 7 15:25:09 UTC 2023 x86_64 + +The programs included with the Debian GNU/Linux system are free software; +the exact distribution terms for each program are described in the +individual files in /usr/share/doc/*/copyright. + +Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent +permitted by applicable law. +Last login: Sun Aug 6 09:45:28 2023 from 172.21.0.1 +``` + +From the Autosubmit container, you should be able to connect to the +computing nodes. + +```bash +$ ssh autosubmit@dockerfiles-computing_node-1 +Welcome to OpenSSH Server +5a29566b9914:~$ +logout +Connection to dockerfiles-computing_node-1 closed. +$ ssh autosubmit@dockerfiles-computing_node-2 +Welcome to OpenSSH Server +cff117cd9a67:~$ +logout +Connection to dockerfiles-computing_node-2 closed. +``` diff --git a/dockerfiles/docker-compose.yml b/dockerfiles/docker-compose.yml new file mode 100644 index 000000000..b615ee785 --- /dev/null +++ b/dockerfiles/docker-compose.yml @@ -0,0 +1,54 @@ +version: "3" +services: + autosubmit: + build: + dockerfile: Dockerfile + container_name: autosubmit + # SSH is used for Autosubmit jobs, not for users to connect. + entrypoint: sudo /usr/sbin/sshd -D -e + # Autosubmit needs this, as otherwise the Autosubmit jobs are + # left as zombie/defunct processes inside the container. + init: true + volumes: + # Using named volumes managed by Docker. + - as_database:/app/autosubmit/database + - as_experiments:/app/autosubmit/experiments + # For SSH. + - ./authorized_keys:/home/autosubmit/.ssh/authorized_keys + - ./id_rsa:/home/autosubmit/.ssh/id_rsa + - ./id_rsa.pub:/home/autosubmit/.ssh/id_rsa.pub + # TODO: For GUI/X we could use something similar to (but + # but there are security issues doing so...) + # - /tmp/.X11-unix/:/tmp/.X11-unix/ + # TODO: We would also need to add to the service: + # environment: + # - DISPLAY=$DISPLAY + ports: + - "22" + restart: unless-stopped + depends_on: + - computing_node + # Our computing nodes. + computing_node: + image: lscr.io/linuxserver/openssh-server:latest + # container_name: openssh-server + # hostname: node-01 + environment: + - PUID=1000 + - PGID=1000 + - TZ=Etc/UTC + - USER_NAME=autosubmit + - PUBLIC_KEY_FILE=/app/id_rsa.pub + - SUDO_ACCESS=false + - PASSWORD_ACCESS=false + # Not documented. Not supported. But works. + # https://github.com/linuxserver/docker-openssh-server/issues/30#issuecomment-1538129057 + - LISTEN_PORT=22 + volumes: + - ./id_rsa.pub:/app/id_rsa.pub + ports: + - "22" + restart: unless-stopped +volumes: + as_database: {} + as_experiments: {} diff --git a/dockerfiles/test.sh b/dockerfiles/test.sh new file mode 100755 index 000000000..020436e97 --- /dev/null +++ b/dockerfiles/test.sh @@ -0,0 +1,112 @@ +#!/bin/bash + +# TODO: this is a temporary test script, to help others to +# review our Docker files. Replace it by a proper test +# once our CICD adds support to containers. + +# This file contains scripts identical or very similar to +# what is described in README.md. The main differences are: +# +# - It builds the image with --no-cache (to force rebuild) +# - It builds the image with the tag :test (and removes it) +# - It runs the container with --detached +# - Tries to set up and clean before/after running all tests +# +# Trap errors and print a message that can be grep'ed. + +set -eux + +setup() { + # Create directories for database and experiments. + rm -rf /tmp/autosubmit/ + mkdir -pv /tmp/autosubmit/{database,experiments} +} + +teardown() { + echo "*** CLEANING UP ***" + docker rm -f -v test-autosubmit || true + rm -rf /tmp/autosubmit/ + docker image rm -f ${USER}/autosubmit:test || true +} + +handle_errors() { + echo "*** ERROR TESTING DOCKER COMMANDS ***" 1>&2 + teardown + exit 1 +} + +trap handle_errors ERR + +setup + +# Test commands. + +# Build. + +docker build \ + --no-cache \ + -t ${USER}/autosubmit:test \ + . + +# Print version. + +docker run --rm --init ${USER}/autosubmit:test \ + autosubmit --version + +# Create external DB. + +docker run --rm \ + -v /tmp/autosubmit/database:/app/autosubmit/database \ + -v /tmp/autosubmit/experiments:/app/autosubmit/experiments \ + ${USER}/autosubmit:test \ + autosubmit install + +# Create a dummy experiment. + +docker run --rm \ + -v /tmp/autosubmit/database:/app/autosubmit/database \ + -v /tmp/autosubmit/experiments:/app/autosubmit/experiments \ + ${USER}/autosubmit:test \ + autosubmit expid -H local -d test --dummy + +# List experiments. + +docker run --rm \ + -v /tmp/autosubmit/database:/app/autosubmit/database \ + -v /tmp/autosubmit/experiments:/app/autosubmit/experiments \ + ${USER}/autosubmit:test \ + autosubmit describe + +# Delete the experiment created. + +docker run --rm \ + -v /tmp/autosubmit/database:/app/autosubmit/database \ + -v /tmp/autosubmit/experiments:/app/autosubmit/experiments \ + ${USER}/autosubmit:test \ + autosubmit delete -f a000 + +# Start the container with SSH (no terminal, dettached). + +docker run --init \ + --detach \ + --name test-autosubmit \ + -ti \ + -p 2222:22 \ + -e DISPLAY=$DISPLAY \ + -v $(pwd -P)/id_rsa:/home/autosubmit/.ssh/id_rsa \ + -v $(pwd -P)/id_rsa.pub:/home/autosubmit/.ssh/id_rsa.pub \ + -v $(pwd -P)/authorized_keys:/home/autosubmit/.ssh/authorized_keys \ + -v /tmp/.X11-unix/:/tmp/.X11-unix/ \ + ${USER}/autosubmit:test /bin/bash + +# Create a dummy experiment again. + +docker exec \ + test-autosubmit \ + autosubmit expid -H local -d test --dummy + +teardown + +echo "*** BYE ***" + +exit 0 -- GitLab