anujdatar / cups-docker

CUPS server running in a docker container
GNU General Public License v3.0
92 stars 27 forks source link

Enable CUPS auto discovery #9

Open Zen3515 opened 9 months ago

Zen3515 commented 9 months ago

I saw your attempt to enable auto-discovery in this commit added avahi-daemon, and exposed port 5353/udp for multicast dns

While that's the correct direction, the normal linux systemd work in a little more complex way.
Specifically, compare to a normal working service, you also need to start process avahi-daemon.service and cups-browsed.service

You can look here

As you can see, it's quite complex to start all the services using your entrypoint.

In order to accomplish that you could take a look at supervisord and tini or my prefered method s6-overlay.

With s6-overlay, you could create many services. Take a look at an example below (generated by ChatGPT)

The s6-overlay is a powerful init system designed for use with Docker containers, allowing you to manage multiple processes within a single container. Here's a basic guide on how to use s6-overlay in a Dockerfile to start multiple processes:

  1. Create a Dockerfile:

    Create a new Dockerfile for your application. Here's a basic example:

    FROM your-base-image
    
    # Install s6-overlay
    ADD https://github.com/just-containers/s6-overlay/releases/download/v2.2.0.3/s6-overlay-amd64.tar.gz /tmp/
    RUN tar xzf /tmp/s6-overlay-amd64.tar.gz -C / \
        && rm /tmp/s6-overlay-amd64.tar.gz
    
    # Add your application files
    COPY ./app /app
    
    # Add s6 service definitions
    COPY ./services /etc/services.d
    
    # Command to start s6-init
    CMD ["/init"]

    In this example, replace your-base-image with the base image you want to use, and ./app with the path to your application files.

  2. Create a services directory:

    Create a directory called services in the same directory as your Dockerfile. Inside this directory, you will define service scripts for each process you want to run.

    For example, if you want to run two processes, create files like services/app1/run and services/app2/run. The contents of these files might look like:

    # services/app1/run
    #!/usr/bin/with-contenv sh
    
    exec /app/app1
    # services/app2/run
    #!/usr/bin/with-contenv sh
    
    exec /app/app2

    These scripts will be executed by s6 when the container starts.

  3. Build your Docker image:

    Run the following command to build your Docker image:

    docker build -t your-image-name .
  4. Run your Docker container:

    Now, you can run your Docker container:

    docker run -d your-image-name

The s6-overlay will manage the specified processes, and you can scale this approach to include more services as needed. The key is to create service scripts in the services directory, and s6 will take care of starting and managing those services within the Docker container.

Zen3515 commented 9 months ago

Essentially, you need to create three services.

And modify your Dockerfile accordingly.

FROM debian:stable-slim

# ENV variables
ENV DEBIAN_FRONTEND noninteractive
ENV TZ "America/New_York"
ENV CUPSADMIN admin
ENV CUPSPASSWORD password

LABEL org.opencontainers.image.source="https://github.com/anujdatar/cups-docker"
LABEL org.opencontainers.image.description="CUPS Printer Server"
LABEL org.opencontainers.image.author="Anuj Datar <anuj.datar@gmail.com>"
LABEL org.opencontainers.image.url="https://github.com/anujdatar/cups-docker/blob/main/README.md"
LABEL org.opencontainers.image.licenses=MIT

# Install s6-overlay
ADD https://github.com/just-containers/s6-overlay/releases/download/v2.2.0.3/s6-overlay-amd64.tar.gz /tmp/

# Install dependencies
RUN apt-get update -qq  && apt-get upgrade -qqy \
    && apt-get install -qqy \
    apt-utils \
    usbutils \
    cups \
    cups-filters \
    printer-driver-all \
    printer-driver-cups-pdf \
    printer-driver-foo2zjs \
    foomatic-db-compressed-ppds \
    openprinting-ppds \
    hpijs-ppds \
    hp-ppd \
    hplip \
    avahi-daemon \
    && tar xzf /tmp/s6-overlay-amd64.tar.gz -C / \
    && rm /tmp/s6-overlay-amd64.tar.gz \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

EXPOSE 631
EXPOSE 5353/udp

# Baked-in config file changes
RUN sed -i 's/Listen localhost:631/Listen 0.0.0.0:631/' /etc/cups/cupsd.conf && \
    sed -i 's/Browsing Off/Browsing On/' /etc/cups/cupsd.conf && \
    sed -i 's/<Location \/>/<Location \/>\n  Allow All/' /etc/cups/cupsd.conf && \
    sed -i 's/<Location \/admin>/<Location \/admin>\n  Allow All\n  Require user @SYSTEM/' /etc/cups/cupsd.conf && \
    sed -i 's/<Location \/admin\/conf>/<Location \/admin\/conf>\n  Allow All/' /etc/cups/cupsd.conf && \
    echo "ServerAlias *" >> /etc/cups/cupsd.conf && \
    echo "DefaultEncryption Never" >> /etc/cups/cupsd.conf

# back up cups configs in case used does not add their own
RUN cp -rp /etc/cups /etc/cups-bak
VOLUME [ "/etc/cups" ]

# Add s6 service definitions
COPY ./services /etc/services.d

# Command to start s6-init
CMD ["/init"]

Something along these lines

anujdatar commented 9 months ago

aah, okay thanks.. I do not have a lot of experience with s6, or managing multiple services inside containers. Thanks for the examples. I honestly did not get a lot of time to experiment over the holidays. I literally only got a couple of hours to work on it, I know it doesn't work yet. I'll hopefully get to work on it again in a few weeks. Work's too busy at the moment.

Anuj

Zen3515 commented 9 months ago

I could help you create this PR, but I have to think about how to incorporate the existing entrypoint script for adding user based on the env variable first.

Zen3515 commented 9 months ago

I've created a PR for this, the only thing left to think about is how to build s6-overlay supporting multiple architecture.

I think you could add a script file which will be executed as one of the Dockerfile steps.

Something like this.

if [[ "${TARGETARCH}" == "amd64" ]]; then
    S6_OVERLAY_ARCH="x86_64"
elif [[ "${TARGETARCH}" == "arm64" ]]; then
    S6_OVERLAY_ARCH="aarch64"
fi

wget -qO- "https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_OVERLAY_ARCH}.tar.xz" |
    tar -C / -Jxpf -

But I'm not sure how we could know the TARGETARCH via github action, based on the quick search, it should be something like this.

...
      - name: Build and push images
        uses: docker/build-push-action@v4
        build-args: |
            TARGETARCH=${{ matrix.arch }}
...

Updated

I found it mentioned here and here, TARGETARCH will be passed automatically with BuildKit.

Which architecture to use depending on your TARGETARCH

The ${arch} part in the s6-overlay-${arch}.tar.xz tarball uses the naming conventions of gcc, which are not the ones that Docker uses. (Everyone does something different in this field depending on their needs, and no solution is better than any other, but the Docker one is worse than others because its naming is inconsistent. The gcc convention is better for us because it simplifies our builds greatly and makes them more maintainable.)

The following table should help you find the right tarball for you if you're using the TARGETARCH value provided by Docker:

${TARGETARCH} ${arch} Notes
amd64 x86_64
arm64 aarch64
arm/v7 arm armv7 with soft-float
arm/v6 armhf Raspberry Pi 1
386 i686 i486 for very old hw
riscv64 riscv64
s390x s390x
Zen3515 commented 9 months ago

I've included multiple architecture support in the PR, it should be ready now.

anujdatar commented 9 months ago

Thanks for all the work. I'll test it out over the weekend and merge the request. Unfortunately I will not be able to get to this till Friday.

Zen3515 commented 9 months ago

That's ok, let me know if any changes are required.

vqndev commented 3 weeks ago

Hi @Zen3515 and @anujdatar thanks for all your work. Was this ever merged? Is there a fork where autodiscovery is working?