Alpine Linux is a lightweight and security-focused Linux distribution that’s widely used in Docker containers. With its small footprint, it’s ideal for building minimalistic containers, but it may not come with all the tools you’re used to on other distributions. For example, services are managed using OpenRC instead of the more commonly known systemd.

In this article, I’ll walk you through the process of setting up and managing a custom service inside an Alpine Linux container, using OpenRC. This could be very useful when you need to run some service alongside your main entrypoint service.

Prerequisites

Before starting, make sure you have the following:

  • A running Alpine Linux container.
  • Basic knowledge of Linux and OpenRC.
  • Access to install packages within the container.

If you’re not familiar with OpenRC, it’s a simple and efficient init system, perfect for resource-constrained environments like Alpine.

Step 1: Installing OpenRC (If Necessary)

First, check if OpenRC is installed in your Alpine container. Many base images come with it pre-installed, but if you’re using a very minimal image, it may be missing. To install OpenRC, run:

apk add openrc

Once installed, OpenRC will provide you with tools to manage system services.

Step 2: Writing the Service Script

Let’s say we want to create a service that monitors a directory for file creation and the new files name automatically. We’ll write a script for this service and place it in /usr/local/bin.

Here’s an example of a monitoring script using inotifywait, which you can install with:

apk add inotify-tools

Create the script:

vi /usr/local/bin/monitor_directory.sh

Add some content like:

#!/bin/sh
DIRECTORY_TO_WATCH="/path/to/directory"
echo $$ > /run/monitor_directory.pid  # Store the PID of this process
inotifywait -m -e create --format '%w%f' "$DIRECTORY_TO_WATCH" | while read NEW_FILE
do
    echo $NEW_FILE"
done

Make the script executable:

chmod +x /usr/local/bin/monitor_directory.sh

This script monitors the directory for file creation events and print the name of the newly created files.

Step 3: Creating the OpenRC Service

Now, let’s create an OpenRC service that manages this script. Services in OpenRC are managed through init scripts located in /etc/init.d. We’ll create one for our file monitoring service.
If you don’t find the /etc/init.d folder, than you need to install the util-linux package:

apk add util-linux

Create the service file:

vi /etc/init.d/monitor_directory

Paste the following content:

#!/sbin/openrc-run

name="Monitor Directory"
description="Monitor a directory"
command="/usr/local/bin/monitor_directory.sh"
command_background=true
pidfile="/run/monitor_directory.pid"

Make the service file executable:

chmod +x /etc/init.d/monitor_directory

Step 4: Using command_background=true and pidfile

In the service script, we set command_background=true, which tells OpenRC to run the script in the background. When running a process in the background, it’s important to also specify a pidfile. This is a file where the process writes its PID (process ID), allowing OpenRC to track the running process.

In our case, the pidfile is located at /run/monitor_directory.pid, and the script writes its own PID to this file using the following line:

echo $$ > /run/monitor_directory.pid

The combination of command_background=true and pidfile ensures that OpenRC can correctly manage the background service, allowing you to start, stop, and restart it.



Step 5: Enabling and Starting the Service

Once the service script is ready, we need to enable it to start at boot and start it immediately. To be sure that the container will run at the desired runlevel (which is debug) we can execute the following command:

openrc default

To add the service to the default runlevel so it starts on boot:

rc-update add monitor_directory default

To start the service manually without rebooting:

service monitor_directory start

Step 6: Dockerfile and Entrypoint for Your Alpine Service

To set up your Alpine Linux container with the custom service you created, you’ll need to define a Dockerfile and an entrypoint script. This will ensure that the service starts automatically when the container is launched.

Here’s how you can structure the Dockerfile and the entrypoint script.

Dockerfile

FROM alpine:latest

RUN apk update && \
    apk add openrc inotify-tools && \
    mkdir -p /run/openrc && \
    touch /run/openrc/softlevel

COPY monitor_directory.sh /usr/local/bin/monitor_directory.sh

COPY monitor_directory_service /etc/init.d/monitor_directory

RUN chmod +x /usr/local/bin/monitor_directory.sh && \
    chmod +x /etc/init.d/monitor_directory

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

entrypoint.sh

#!/bin/sh

openrc default

rc-update add monitor_directory default

rc-service monitor_directory start

exec "$@"

Conclusion

By configuring the Dockerfile and the entrypoint correctly, you can build a Docker container that not only runs your custom service inside Alpine Linux but also ensures that the service starts automatically when the container is launched. This makes it easy to manage services in a lightweight container environment.

Alpine Linux’s minimalism and OpenRC’s simplicity make this a perfect combination for containerized environments, where efficiency and control are key.


Troubleshooting

  1. Service Fails to Start:
    Check the /var/log/messages or /var/log/rc.log files for any errors.
  2. PID File Not Found:
    Make sure your script writes the PID to the pidfile location specified in the service script. You can check this by manually starting the script and inspecting the contents of /run/monitor_directory.pid.
  3. Services Not Persisting Across Reboots:
    If your service isn’t starting automatically after a reboot, verify that it’s added to the default runlevel with rc-update.

By following these steps, you should be able to set up any service in an Alpine Linux container and manage it effectively.