init: Implement pre-initialization hooks (#269)

* Implement pre-initialization hooks

This implements support for running commands prior to most of the
container initialization. e.g. for RHEL and derivatives you might need
to pre-enable the PowerTools/CRB and EPEL repositories.

Resolves: #220

```
distrobox on  main [!⇡]
✦ ❯ ./distrobox create -i registry.fedoraproject.org/fedora-toolbox:36 f36-packaging
a3cc54e5a820b6bd95286ec142cb3eeab7f72b42cebf6fa0d3c0072035b3bca4
Distrobox 'f36-packaging' successfully created.
To enter, run:

distrobox-enter f36-packaging

distrobox on  main [!⇡]
✦ ❯ ./distrobox enter f36-packaging
Container f36-packaging is not runnung.
Starting container f36-packaging
run this command to follow along:

 podman logs -f f36-packaging

 Starting container...                  	 [ OK ]
 Installing basic packages...           	 [ OK ]
 Setting up read-only mounts...         	 [ OK ]
 Setting up read-write mounts...        	 [ OK ]
 Setting up host's sockets integration...	 [ OK ]
 Integrating host's themes, icons, fonts...	 [ OK ]
 Setting up package manager exceptions...	 [ OK ]
 Setting up sudo...                     	 [ OK ]
 Setting up groups...                   	 [ OK ]
 Setting up users...                    	 [ OK ]
 Executing init hooks...                	 [ OK ]

Container Setup Complete!
Welcome to fish, the friendly interactive shell
Type help for instructions on how to use fish

distrobox on  main [!⇡]
⬢ [fedora-toolbox:36] ❯
```

Enable PowerTools (recommended to use EPEL) and EPEL Next, so
`distrobox` can install the Fish shell.

```
distrobox on  main [!⇡]
✦ ❯ ./distrobox create -i quay.io/centos/centos:stream8 c8s --pre-init-hooks "dnf config-manager --enable powertools && dnf -y install epel-next-release"
9b17e8cfbf8e7a26abdc7a78b2325e1ee4a9577662b0fe94fbde4260269e1ce3
Distrobox 'c8s' successfully created.
To enter, run:

distrobox-enter c8s

distrobox on  main [!⇡]
✦ ❯ ./distrobox enter c8s
Container c8s is not runnung.
Starting container c8s
run this command to follow along:

 podman logs -f c8s

 Starting container...                  	 [ OK ]
 Executing pre-init hooks...            	 [ OK ]
 Installing basic packages...           	 [ OK ]
 Setting up read-only mounts...         	 [ OK ]
 Setting up read-write mounts...        	 [ OK ]
 Setting up host's sockets integration...	 [ OK ]
 Integrating host's themes, icons, fonts...	 [ OK ]
 Setting up package manager exceptions...	 [ OK ]
 Setting up sudo...                     	 [ OK ]
 Setting up groups...                   	 [ OK ]
 Setting up users...                    	 [ OK ]
 Executing init hooks...                	 [ OK ]

Container Setup Complete!
Welcome to fish, the friendly interactive shell
Type help for instructions on how to use fish

distrobox on  main
⬢ [centos:stream8] ❯
```

Signed-off-by: Michel Alexandre Salim <michel@michel-slm.name>

* Fix typo: s/runnung/running

Signed-off-by: Michel Alexandre Salim <michel@michel-slm.name>

* simplify pre-init-hooks detection, add useful tips

Signed-off-by: Michel Alexandre Salim <michel@michel-slm.name>

* More changes to address review feedback

- distrobox-init: indent new if block
- distrobox-create: restore quote around pre-init-hooks arguments
- docs/usage: document new create and init options
- docs/useful_tips: explain the rationale behind --pre-init-hooks

Signed-off-by: Michel Alexandre Salim <michel@michel-slm.name>
This commit is contained in:
Michel Alexandre Salim
2022-05-15 11:14:24 -07:00
committed by GitHub
parent 094894e2fe
commit 62dd2fda8f
6 changed files with 54 additions and 3 deletions

View File

@@ -47,6 +47,7 @@ container_init_hook=""
container_manager="autodetect"
container_manager_additional_flags=""
container_name=""
container_pre_init_hook=""
container_user_custom_home=""
container_user_gid="$(id -rg)"
container_user_home="${HOME:-"/"}"
@@ -105,7 +106,7 @@ Usage:
distrobox create --image fedora:35 --name test --volume /opt/my-dir:/usr/local/my-dir:rw --additional-flags "--pids-limit -1"
distrobox create --image fedora:35 --name test --additional-flags "--env MY_VAR-value"
distrobox create --image alpine:latest --name test --init-hooks "touch /var/tmp/test1 && touch /var/tmp/test2"
distrobox create -i docker.io/almalinux/8-init --init --name test
distrobox create -i docker.io/almalinux/8-init --init --name test --pre-init-hooks "dnf config-manager --enable powertools && dnf -y install epel-release"
DBX_NON_INTERACTIVE=1 DBX_CONTAINER_NAME=test-alpine DBX_CONTAINER_IMAGE=alpine distrobox-create
@@ -123,6 +124,7 @@ Options:
--volume additional volumes to add to the container
--additional-flags/-a: additional flags to pass to the container manager command
--init-hooks additional commands to execute during container initialization
--pre-init-hooks additional commands to execute prior to container initialization
--init/-I use init system (like systemd) inside the container.
this will make host's processes not visible from within the container.
--help/-h: show this message
@@ -219,6 +221,13 @@ while :; do
shift
fi
;;
--pre-init-hooks)
if [ -n "$2" ]; then
container_pre_init_hook="--pre-init-hooks \"${2}\""
shift
shift
fi
;;
--) # End of all options.
shift
break
@@ -517,6 +526,7 @@ generate_command() {
--group ${container_user_gid}
--home \"${container_user_custom_home:-"${container_user_home}"}\"
--init \"${init}\"
${container_pre_init_hook}
-- '${container_init_hook}'
"
# use container_user_custom_home if defined, else fallback to normal home.

View File

@@ -383,7 +383,7 @@ if [ "${container_status}" != "running" ]; then
# Here, we save the timestamp before launching the start command, so we can
# be sure we're working with this very same session of logs later.
printf >&2 "Container %s is not runnung.\n" "${container_name}"
printf >&2 "Container %s is not running.\n" "${container_name}"
printf >&2 "Starting container %s\n" "${container_name}"
printf >&2 "run this command to follow along:\n\n"
printf >&2 " %s logs -f %s\n\n" "${container_manager}" "${container_name}"

View File

@@ -29,6 +29,7 @@ trap '[ "$?" -ne 0 ] && printf "Error: An error occurred\n"' EXIT
# Defaults
init=0
init_hook=""
pre_init_hook=""
verbose=0
version="1.2.16"
# Print usage to stdout.
@@ -52,6 +53,7 @@ Options:
--home/-d: path/to/home of the user
--help/-h: show this message
--init/-I: whether to use or not init
--pre-init-hooks: commands to execute prior to init
--verbose/-v: show more verbosity
--version/-V: show version
--: end arguments execute the rest as command to execute during init
@@ -109,6 +111,13 @@ while :; do
shift
fi
;;
--pre-init-hooks)
if [ -n "$2" ]; then
pre_init_hook="$2"
shift
shift
fi
;;
--)
shift
init_hook=$*
@@ -195,6 +204,14 @@ mount_bind() (
return 0
)
if [ -n "${pre_init_hook}" ]; then
printf "distrobox: Executing pre-init hooks...\n"
# execute pre-init hooks if specified
# shellcheck disable=SC2086
eval ${pre_init_hook}
fi
printf "distrobox: Installing basic packages...\n"
# Extract shell name from the $SHELL environment variable
# If not present as package in the container, we want to install it.

View File

@@ -14,7 +14,7 @@ Usage:
distrobox create --image fedora:35 --name test --volume /opt/my-dir:/usr/local/my-dir:rw --additional-flags "--pids-limit -1"
distrobox create --image fedora:35 --name test --additional-flags "--env MY_VAR-value"
distrobox create --image alpine:latest --name test --init-hooks "touch /var/tmp/test1 && touch /var/tmp/test2"
distrobox create -i docker.io/almalinux/8-init --init --name test
distrobox create -i docker.io/almalinux/8-init --init --name test --pre-init-hooks "dnf config-manager --enable powertools && dnf -y install epel-release"
You can also use environment variables to specify container name and image
@@ -40,6 +40,7 @@ Options:
--volume additional volumes to add to the container
--additional-flags/-a: additional flags to pass to the container manager command
--init-hooks additional commands to execute during container initialization
--pre-init-hooks additional commands to execute prior to container initialization
--init/-I use init system (like systemd) inside the container.
this will make host's processes not visible from within the container.
--help/-h: show this message

View File

@@ -24,6 +24,7 @@ Options:
--home/-d: path/to/home of the user
--help/-h: show this message
--init/-I: whether to use or not init
--pre-init-hooks: commands to execute prior to init
--verbose/-v: show more verbosity
--version/-V: show version
--: end arguments execute the rest as command to execute during init

View File

@@ -16,6 +16,7 @@
- [Slow creation on podman and image size getting bigger with distrobox create](#slow-creation-on-podman-and-image-size-getting-bigger-with-distrobox-create)
- [Container save and restore](#container-save-and-restore)
- [Check used resources](#check-used-resources)
- [Pre-installing additional package repositories](#pre-installing-additional-package-repositories)
- [Build a Gentoo distrobox container](distrobox_gentoo.md)
- [Build a Dedicated distrobox container](distrobox_custom.md)
@@ -278,3 +279,24 @@ in simple (and scriptable) steps.
- You can always check how much space a `distrobox` is taking by using `podman` command:
`podman system df -v` or `docker system df -v`
## Pre-installing additional package repositories
On Red Hat Enterprise Linux and its derivatives, the amount of packages in the
base repositories is limited, and additional packages need to be brought in by
enabling additional repositories such as [EPEL](https://docs.fedoraproject.org/en-US/epel/).
You can use `--init-hooks` to automate this, but this does not solve the
issue for package installations done during initialization itself, e.g. if
the shell you use on the host is not available in the default repos (e.g.
`fish`).
Use the pre-initialization hooks for this:
```bash
distrobox create -i docker.io/almalinux/8-init --init --name test --pre-init-hooks "dnf config-manager --enable powertools && dnf -y install epel-release"
```
```bash
distrobox create -i quay.io/centos/centos:stream8 c8s --pre-init-hooks "dnf config-manager --enable powertools && dnf -y install epel-next-release"
```