Skip to content

Commit

Permalink
Add support for rootless docker via contexts (#18)
Browse files Browse the repository at this point in the history
Context support added under module config
Added development environment for testing rootless docker
  • Loading branch information
dave-lang authored Dec 13, 2024
1 parent cbf18fd commit 9a28d9e
Show file tree
Hide file tree
Showing 10 changed files with 203 additions and 38 deletions.
59 changes: 50 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@ Alternatively you can download and install it directly from the [releases page](

Once installed a new option 'Docker Containers' will appear in the menu under 'Servers'.

## Rootless Docker

Experimental rootless docker support has been added via [docker contexts](https://docs.docker.com/engine/manage-resources/contexts/). To use this module with rootless docker:
- Ensure you have a [context setup](https://docs.docker.com/engine/manage-resources/contexts/#create-a-new-context), you can do this via:
- Open a terminal as the user rootless dockerd runs as
- Run `id -u` to check the current user id
- Check the docker.sock file path matches the user id, you can see the running service using `ps -al`
- Run `docker context create rootless --docker "host=unix:///run/user/$(id -u)/docker.sock"`
- If you want to always use this context, run `docker context use rootless`
- If you didn't change the docker context via command:
- Once created, in the module screen click either 'Module config' or the cog icon to the left of the header
- Set the context override to match your new context, e.g. `rootless`

## Functionality

### Container listing/actions
<img width="1728" alt="image" src="https://github.com/user-attachments/assets/58de37c1-2f8b-42d9-9b49-ea9f541f9e53">

Expand All @@ -40,21 +55,47 @@ Improvements or fixes are welcome, please raise it under issues and link to your

Docker configuration has been setup to allow easier development.

This environment has Webmin and Docker already installed, along with a very basic Ubuntu 18 docker config ready to start in the container (Docker in Docker).

The plugin is installed in the Webmin environment via shared folder, changes will appear immediately. This is done via:
- Sharing the ./docker directory into webmin directory using Docker volume (see docker-compose.yml)
- Adding the ACL permission for the module via the Dockerfile
The development environment creates 2 containers:
- webmin_master - Webmin on focal ubuntu with docker & webmin auto start, available on port 10000 on the host
- docker_dd - DIND container with rootless docker and webmin, available on port 20000 on the host (DOES NOT AUTO START). Very hacky.

### To use
1. `cd tools`
2. `docker-compose up -d` to run docker compose as daemon
3. Open http://localhost:10000 to access the webmin console
4. Login is `root` + `password`, this can be adjusted in the Dockerfile
1. `docker-compose up -d` to run docker compose as daemon
1. Open http://localhost:10000 to access the webmin console for docker on Ubuntu
1. If you want to test rootless docker, run `docker exec -it --user root:root docker_dd /etc/webmin/start`
1. Open http://localhost:20000 to access the webmin console for rootless docker
1. Login on both envs is `root` + `password`, this can be adjusted in the Dockerfile
1. The config file will not automatically be loaded due to locking issues, you will need to run:
1. `docker exec -it --user root:root webmin_master sh -c 'cp /usr/share/webmin/docker/config /etc/webmin/docker'`
1. `docker exec -it --user root:root docker_dd sh -c 'cp /usr/local/webmin/docker/config /etc/webmin/docker'`

To burn and recreate the environment use `docker-compose down -v`

#### webmin_master
This environment has Webmin and Docker already installed, along with a very basic docker config ready to start in the container (Docker in Docker in Docker?).

The plugin is installed in the Webmin environment via shared folder, changes will appear immediately. This is done via:
- Sharing the ./docker directory into webmin directory using Docker volume (see docker-compose.yml)
- Adding the ACL permission for the module via the Dockerfile

Use `docker exec -it webmin_master /bin/bash` to get a SSH console.

Docker will not be running by default, use `dockerd` to run it, Ctrl+C to stop. Start the internal container via:
Start the internal container via:
1. `cd dind`
2. `docker-compose up -d`

#### docker_dd

Hacky webmin on DIND rootless container to allow for rootless docker testing. Webmin doesn't auto start, you will need to open a terminal and:
- `docker exec -it --user root:root docker_dd /etc/webmin/start`
- To setup a docker context for testing:
- `docker exec -it docker_dd /bin/sh`
- `docker context create rootless --docker "host=unix:///run/user/$(id -u)/docker.sock"`
- In the webmin module conf, change to use the rootless context or run `docker context use rootless`

To start a test container
1. `cd /home/dind`
2. `docker-compose --context rootless up -d`

Use `docker exec -it docker_dd /bin/sh` to get a console.
1 change: 1 addition & 0 deletions docker/config
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docker_context=default
1 change: 1 addition & 0 deletions docker/config.info
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docker_context=Override the docker context,0
9 changes: 8 additions & 1 deletion docker/docker-lib.pl
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,23 @@
init_config();

sub docker_command {
our (%config);
my($command, $format, $safe) = @_;
$format ||= "";
my $context = "";
$safe ||= 1;

if ($format) {
$format = ' --format "' . $format . '"'
}

# If there's a context set, use it
if ($config{'docker_context'}) {
$context = ' --context "' . $config{'docker_context'} . '"';
}

my ($result, $fail);
my $code = execute_command('docker ' . $command . $format, undef, \$result, \$fail, 0, $safe);
my $code = execute_command('docker' . $context . ' ' . $command . $format, undef, \$result, \$fail, 0, $safe);

if ($code != 0) {
return $code, $fail;
Expand Down
48 changes: 45 additions & 3 deletions docker/index.cgi
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@ use Data::Dumper;

require './docker-lib.pl';

ui_print_header(undef, &text('index_title'), "", undef, undef, 1);
ui_print_header(undef, &text('index_title'), "", undef, 1, 1);

if (!&has_command('docker')) {
&ui_print_endpage(&text('not_installed')); #, "<tt>$config{'syslog_conf'}</tt>", "../config.cgi?$module_name"));
}

our (%config);

if ($config{'docker_context'}) {
print ui_alert_box('Using docker context: ' .
html_escape($config{'docker_context'}) . ' ' . &help_search_link("docker context", "google"), 'warn');
}

my @tabs = ( [ 'info', &text('tab_info') ],
[ 'containers', &text('tab_containers') ] );

Expand All @@ -23,7 +30,7 @@ if ($status_fail) {
print ui_alert_box($status_fail, 'danger');
} else {
#print circular_grid($status); # Ugly recursive output
print "<pre>" . $status . "</pre>";
print "<pre>" . html_escape($status) . "</pre>";
}
print ui_tabs_end_tab('mode', 'info');

Expand All @@ -39,7 +46,42 @@ if ($fail) {
print &ui_submit(text('label_refresh'));
print &ui_form_end(),"<br>\n";

print '<style>.panel-body tr td { padding: 5px 10px 7px 10px !important} </style>';
# Provide some basic responsive support across all themes
print '<style>
.panel-body tr td { padding: 5px 10px 7px 10px !important}
.visible-xs,.visible-sm,.visible-md,.visible-lg {
display: none !important
}
@media(max-width: 767px) {
.visible-xs {
display:block !important
}
}
@media(max-width: 767px) {
.hidden-xs {
display:none !important
}
}
@media(min-width: 768px) and (max-width:991px) {
.hidden-sm {
display:none !important
}
}
@media(min-width: 992px) and (max-width:1199px) {
.hidden-md {
display:none !important
}
}
@media(min-width: 1200px) {
.hidden-lg {
display:none !important
}
}</style>';

print &ui_columns_start([
&text('label_name'),
Expand Down
18 changes: 17 additions & 1 deletion tools/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,27 @@ services:
container_name: webmin_master
privileged: true
build:
context: ./
context: ./docker
volumes:
- ../docker:/usr/share/webmin/docker:rw # This also requires the ACL permission to load in Webmin, see dockerfile
#- ../docker/config:/etc/webmin/docker/config:rw # breaks editing config in portal
- ./dind:/home/dind:rw
ports:
- "10000:10000"
cap_add:
- NET_ADMIN
dockerdd:
#image: docker:27-dind-rootless
container_name: docker_dd
privileged: true
build:
context: ./docker-dind
dockerfile: ./Dockerfile
volumes:
- ../docker:/usr/local/webmin/docker:rw # This also requires the ACL permission to load in Webmin, see dockerfile
#- ../docker/config:/etc/webmin/docker/config:rw # breaks editing config in portal
- ./dind:/home/dind:rw
ports:
- "20000:10000"
cap_add:
- NET_ADMIN
32 changes: 32 additions & 0 deletions tools/docker-dind/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Use the latest Ubuntu image as a parent
FROM docker:27-dind-rootless

USER root

# Install Webmin on DIND container
RUN set -eux; \
echo "root:root" | chpasswd && \
apk add perl perl-net-ssleay expect

COPY webmin.exp /

WORKDIR /opt

RUN set -eux; \
wget -O - https://github.com/webmin/webmin/archive/refs/tags/2.202.tar.gz | tar -xzf - && \
mv webmin-2.202 webmin && \
/usr/bin/expect /webmin.exp && \
echo "$(cat /etc/webmin/webmin.acl) docker" > /etc/webmin/webmin.acl && \
mkdir /etc/webmin/docker

# Last 2 line adds docker module to webmin's acl, for easier development and creates the config dir.
# Also requires the volume & config in the compose file

EXPOSE 10000

ENV LC_ALL C.UTF-8

WORKDIR /home


#USER rootless
16 changes: 16 additions & 0 deletions tools/docker-dind/webmin.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/expect

set timeout -1
spawn "/opt/webmin/setup.sh" /usr/local/webmin
expect "Config file directory " {send "\r"}
expect "Log file directory " {send "/var/log/webmin\r"}
expect "Full path to perl (default /usr/bin/perl):" {send "\r"}
expect "Operating system:" {send "84\r"}
expect "Version:" {send "ES4.0\r"}
expect "Web server port (default 10000):" {send "\r"}
expect "Login name (default admin):" {send "root\r"}
expect "Login password:" {send "password\r"}
expect "Password again:" {send "password\r"}
expect "Use SSL (y/n):" {send "n\r"}
expect "Start Webmin at boot time (y/n):" {send "y\r"}
expect eof
47 changes: 23 additions & 24 deletions tools/Dockerfile → tools/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Use the latest Ubuntu image as a parent
FROM ubuntu:focal
FROM cruizba/ubuntu-dind:focal-27.3.1

ENV DEBIAN_FRONTEND=noninteractive TZ=Australia/Brisbane

Expand All @@ -8,40 +8,39 @@ ENV DEBIAN_FRONTEND=noninteractive TZ=Australia/Brisbane
RUN apt-get update -qq -y && \
apt-get upgrade -y && \
apt-get install -y \
wget \
curl \
apt-transport-https \
lsb-release \
ca-certificates \
# wget \
# curl \
# apt-transport-https \
# lsb-release \
# ca-certificates \
gnupg2 \
software-properties-common \
locales \
cron \
net-tools \
vim \
docker \
docker-compose
RUN dpkg-reconfigure locales
# software-properties-common \
# locales \
# cron \
net-tools
# vim \
# docker \
# docker-compose
# RUN dpkg-reconfigure locales

# Install Webmin
RUN echo root:password | chpasswd && \
echo "Acquire::GzipIndexes \"false\"; Acquire::CompressionTypes::Order:: \"gz\";" >/etc/apt/apt.conf.d/docker-gzip-indexes && \
update-locale LANG=C.UTF-8 && \
# update-locale LANG=C.UTF-8 && \
echo deb https://download.webmin.com/download/repository sarge contrib >> /etc/apt/sources.list && \
wget http://www.webmin.com/jcameron-key.asc && \
apt-key add jcameron-key.asc && \
apt-get update && \
apt-get install -y webmin && \
apt-get clean && \
echo "$(cat /etc/webmin/webmin.acl) docker" > /etc/webmin/webmin.acl
# Last line adds docker module to webmin's acl, for easier development. Also requires the volume config
# apt-get clean && \
echo "$(cat /etc/webmin/webmin.acl) docker" > /etc/webmin/webmin.acl && \
mkdir /etc/webmin/docker

# Last 2 line adds docker module to webmin's acl, for easier development and creates the config dir.
# Also requires the volume & config in the compose

EXPOSE 10000
ENV LC_ALL C.UTF-8

WORKDIR /home
RUN echo "#! /bin/bash" > entrypoint.sh && \
echo "sed -i 's;ssl=1;ssl=0;' /etc/webmin/miniserv.conf && systemctl enable cron && service webmin start && tail -f /dev/null" >> entrypoint.sh && \
chmod 755 entrypoint.sh

CMD /home/entrypoint.sh
COPY entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/entrypoint.sh
10 changes: 10 additions & 0 deletions tools/docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash

# Start docker
start-docker.sh

# Your commands go here
sed -i 's;ssl=1;ssl=0;' /etc/webmin/miniserv.conf
# systemctl enable cron
service webmin start
tail -f /dev/null

0 comments on commit 9a28d9e

Please sign in to comment.