Skip to content

Instantly share code, notes, and snippets.

@svanellewee
Last active October 11, 2023 14:04
Show Gist options
  • Save svanellewee/ec25c234b61213710771bf25d1cc45d0 to your computer and use it in GitHub Desktop.
Save svanellewee/ec25c234b61213710771bf25d1cc45d0 to your computer and use it in GitHub Desktop.
How to make a kubernetes cups server on a raspberry pi 3 using k3s.

Introduction

  • Me: I want a kubernetes cluster for my nefarious purposes, but I'm a cheapskate who doesnt want to spend money on a DO droplet.
  • Also Me: LOOK! A raspberry pi 3 I'm not using. But wait, it's too small for a k8s cluster.

That's when I decided I wanted a k3s master. It seems a raspberry pi 3 is exactly what I needed.

Requiments

  • Raspberry Pi 3B
  • raspbian (or the artist formerly known as raspbian) raspberry pi os?
  • A static IP. On my router I set up a static ip for my raspberry pi. Thought this might make discovery and kubectl happier if it was always an ip I could count on.

Node Setup

On the router set the raspberry pi's ip to something known. I made mine 192.168.8.200 because that's in the CIDR range used by my router. Makes ssh easier also ie:

ssh pi@192.168.8.200
# raspberry

Install raspberry pi os here

ON THE PI: Disable swap (just like a real kubernetes). On a raspberry pi os, this means:

sudo dphys-swapfile swapoff
sudo systemctl disable dphys-swapfile.service

ON THE PI: Install k3s as per the website:

sudo su
curl -sfL https://get.k3s.io | sh -

ON THE PI: make the kubeconfig available for copy via scp:

cp /etc/rancher/k3s/k3s.yaml  /home/pi

From your laptop copy the kubeconfig:

scp pi@192.168.8.200:k3s.yaml .
export KUBECONFIG=$PWD/k3s.yaml
sed -i 's/127.0.0.1/192.168.8.200/' k3s.yaml   # or whatever IP you selected for the rpi
kubectl get po -A

Congrats, That should be enough for a single node k3s master

Adding cups to your k3s raspberry pi server

Requirements:

  • Cross building of docker images requires buildx

steps:

  • setup the infrastructure:
 { 
   docker run --rm --privileged multiarch/qemu-user-static --reset -p yes;
   docker buildx rm builder;
   docker buildx create --name builder --driver docker-container --use;
   docker buildx inspect --bootstrap; 
 }
  • Build your docker using buildx:
 docker buildx build --platform linux/arm/v7 -t cups:stephan2 . --output type=docker,dest=- > container-data.tar 
  • copy container-data.tar to the raspberry pi and import:
k3s ctr i  import container-data.tar
  • apply all the yaml on the new cluster:
kubectl apply -f configmap.yaml # see the other files in this gist
kubectl apply -f cups-deployment-and-service.yaml

Note that this is a privileged pod, and that it requires to mount the dbus and dev directories.

Then you can navigate to your raspberrypi-ip:31631 (I changed the default port of the cups server from 631)

Set up your printer from there. If it worked you printer should be visible in the Administration --> Add a printer view.

apiVersion: v1
data:
cupsd.conf: "#\n#\n# Sample configuration file for the CUPS scheduler. See \"man
cupsd.conf\" for a\n# complete description of this file.\n#\n\n# Log general information
in error_log - change \"warn\" to \"debug\"\n# for troubleshooting...\nLogLevel
debug2\n\n# Deactivate CUPS' internal logrotating, as we provide a better one,
especially\n# LogLevel debug2 gets usable now\nMaxLogSize 0\n\n# Listen to all\nPort
31631\nListen /var/run/cups/cups.sock\nListen 127.0.0.1:31631 \n\n# Show shared
printers on the local network.\nBrowsing On\nBrowseLocalProtocols dnssd\n\n# Default
authentication type, when authentication is required...\nDefaultAuthType Basic\nDefaultEncryption
IfRequested\n\n# Web interface setting...\nWebInterface Yes\n\n# Restrict access
to the server...\n<Location />\n Order allow,deny\n Allow all\n</Location>\n\n#
Restrict access to the admin pages...\n<Location /admin>\n Order allow,deny\n
\ Allow all\n</Location>\n\n# Restrict access to configuration files...\n<Location
/admin/conf>\n AuthType Default\n Require user @SYSTEM\n Order allow,deny\n
\ Allow all\n</Location>\n\n# Set the default printer/job policies...\n<Policy
default>\n # Job/subscription privacy...\n JobPrivateAccess default\n JobPrivateValues
default\n SubscriptionPrivateAccess default\n SubscriptionPrivateValues default\n\n
\ # Job-related operations must be done by the owner or an administrator...\n
\ <Limit Create-Job Print-Job Print-URI Validate-Job>\n Order deny,allow\n
\ </Limit>\n\n <Limit Send-Document Send-URI Hold-Job Release-Job Restart-Job
Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription Cancel-Subscription
Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job Resume-Job
Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document>\n Require user @OWNER
@SYSTEM\n Order deny,allow\n </Limit>\n\n # All administration operations
require an administrator to authenticate...\n <Limit CUPS-Add-Modify-Printer
CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class CUPS-Set-Default CUPS-Get-Devices>\n
\ AuthType Default\n Require user @SYSTEM\n Order deny,allow\n </Limit>\n\n
\ # All printer operations require a printer operator to authenticate...\n <Limit
Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job
Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer
Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs
CUPS-Reject-Jobs>\n AuthType Default\n Require user @SYSTEM\n Order deny,allow\n
\ </Limit>\n\n # Only the owner or an administrator can cancel or authenticate
a job...\n <Limit Cancel-Job CUPS-Authenticate-Job>\n Require user @OWNER
@SYSTEM\n Order deny,allow\n </Limit>\n\n <Limit All>\n Order deny,allow\n
\ </Limit>\n</Policy>\n\n# Set the authenticated printer/job policies...\n<Policy
authenticated>\n # Job/subscription privacy...\n JobPrivateAccess default\n
\ JobPrivateValues default\n SubscriptionPrivateAccess default\n SubscriptionPrivateValues
default\n\n # Job-related operations must be done by the owner or an administrator...\n
\ <Limit Create-Job Print-Job Print-URI Validate-Job>\n AuthType Default\n
\ Order deny,allow\n </Limit>\n\n <Limit Send-Document Send-URI Hold-Job Release-Job
Restart-Job Purge-Jobs Set-Job-Attributes Create-Job-Subscription Renew-Subscription
Cancel-Subscription Get-Notifications Reprocess-Job Cancel-Current-Job Suspend-Current-Job
Resume-Job Cancel-My-Jobs Close-Job CUPS-Move-Job CUPS-Get-Document>\n AuthType
Default\n Require user @OWNER @SYSTEM\n Order deny,allow\n </Limit>\n\n
\ # All administration operations require an administrator to authenticate...\n
\ <Limit CUPS-Add-Modify-Printer CUPS-Delete-Printer CUPS-Add-Modify-Class CUPS-Delete-Class
CUPS-Set-Default>\n AuthType Default\n Require user @SYSTEM\n Order deny,allow\n
\ </Limit>\n\n # All printer operations require a printer operator to authenticate...\n
\ <Limit Pause-Printer Resume-Printer Enable-Printer Disable-Printer Pause-Printer-After-Current-Job
Hold-New-Jobs Release-Held-New-Jobs Deactivate-Printer Activate-Printer Restart-Printer
Shutdown-Printer Startup-Printer Promote-Job Schedule-Job-After Cancel-Jobs CUPS-Accept-Jobs
CUPS-Reject-Jobs>\n AuthType Default\n Require user @SYSTEM\n Order deny,allow\n
\ </Limit>\n\n # Only the owner or an administrator can cancel or authenticate
a job...\n <Limit Cancel-Job CUPS-Authenticate-Job>\n AuthType Default\n Require
user @OWNER @SYSTEM\n Order deny,allow\n </Limit>\n\n <Limit All>\n Order
deny,allow\n </Limit>\n</Policy>\n\n#\n#\n"
kind: ConfigMap
metadata:
name: cupsd-conf
namespace: default
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: cups
name: cups
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: cups
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: cups
spec:
containers:
- image: cups:stephan2
imagePullPolicy: IfNotPresent
name: cups
resources: {}
securityContext:
privileged: true
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /etc/cups/ppd/
name: printy-ppd
- mountPath: /etc/cups/
name: cupsd-conf
- mountPath: /var/run/dbus
name: dbus-host-vol
- mountPath: /dev/bus/usb
name: usb-host-vol
dnsPolicy: ClusterFirst
hostIPC: true
hostNetwork: true
hostPID: true
restartPolicy: Always
schedulerName: default-scheduler
securityContext: {}
terminationGracePeriodSeconds: 30
volumes:
- configMap:
defaultMode: 420
items:
- key: cupsd.conf
path: cupsd.conf
name: cupsd-conf
name: cupsd-conf
- hostPath:
path: /tmp/printyppd
type: ""
name: printy-ppd
- hostPath:
path: /var/run/dbus
type: ""
name: dbus-host-vol
- hostPath:
path: /dev/bus/usb
type: ""
name: usb-host-vol
---
apiVersion: v1
kind: Service
metadata:
labels:
app: cups
name: cups
namespace: default
selfLink: /api/v1/namespaces/default/services/cups
spec:
clusterIP: 10.43.105.64
externalTrafficPolicy: Cluster
ports:
- nodePort: 31631
port: 31631
protocol: TCP
targetPort: 31631
selector:
app: cups
sessionAffinity: None
type: NodePort
status:
loadBalancer: {}
# stole this basically from `https://github.com/lemariva/wifi-cups-server`
# creates a docker image `cups:stephan2`
FROM debian:buster
ARG TARGETPLATFORM
ARG BUILDPLATFORM
RUN echo "I am running on $BUILDPLATFORM, building for $TARGETPLATFORM"
RUN apt-get update && apt-get install -y \
sudo \
locales \
whois \
cups \
cups-client \
cups-bsd \
printer-driver-all \
printer-driver-gutenprint \
hpijs-ppds \
hp-ppd \
hplip \
printer-driver-foo2zjs
ENV LANG=en_US.UTF-8 \
LC_ALL=en_US.UTF-8 \
LANGUAGE=en_US:en
RUN useradd \
--groups=sudo,lp,lpadmin \
--create-home \
--home-dir=/home/print \
--shell=/bin/bash \
--password=$(mkpasswd print) \
print \
&& sed -i '/%sudo[[:space:]]/ s/ALL[[:space:]]*$/NOPASSWD:ALL/' /etc/sudoers \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
&& mkdir /var/lib/apt/lists/partial
# Might not be necessary since we are using configmaps now.
# alternatively make a `etc-cups` directory with a default `cupsd.conf`
# COPY etc-cups/cupsd.conf /etc/cups/cupsd.conf
EXPOSE 631
ENTRYPOINT ["/usr/sbin/cupsd", "-f"]
@svanellewee
Copy link
Author

Note I deviate from the original Dockerfile in using a configmap. I did however make the image with a default configmap originally just like
https://github.com/lemariva/wifi-cups-server did, but am now overriding it.

@Brice187
Copy link

Tabs can not be encoded properly in yaml. If you get rid of \t you can make your Configmap human-readable

@sayantandas
Copy link

Hello @svanellewee , thank you for posting your code. I tried working with your code on Openshift locally on my laptop. I had to make some modifications to the yaml and the cupsd.conf to get it deployed. After deployment i'm facing two issues.

  1. logs do not show up anywhere for the pods
  2. while trying to add a printer, every time I click on add a printer, I get the following error "Request Entity Too Large" .
    Do you have any idea how to fix these?
    The modified files are here https://github.com/sayantandas/cups-ocp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment