cupsサーバ on Docker

【[当研究室のシステム]】

# 概要
[cupsサーバ on Ubuntu Server]をベースに，Docker上にcupsサーバを構築．

## 更新履歴
2023/02/17: 間違い修正
2023/02/13: インストール用スクリプトをvolume(bind)経由で使用することに変更．
2023/02/15: [総評](#総評)追加

## はまりポイント
### lpadmin
`lpadmin`でプリンタの設定を行う．このコマンドは/etc/cups/printer.confを作成・記述を行うが，これが非同期で`lpadmin`の実行後30秒くらいかかるらしい([Dockerfile RUN lpadmin to add a printer not working in the built image?])．その為，Dockerfileの中に`RUN lpadmin ...`を書いてもイメージに反映してくれない．`RUN lpadmin ...`はDockerfileの中ではなくインタラクティブ(`docker container exec -it ...`)に実行して`commit`する必要がある．

### lpdプロトコルの使用
~~lpdプロトコルは515ポートを使用するので開けておく必要がある．~~
lpdはTCP515を使うけど，cupsによるサービス待受けじゃないのでポート開けておく必要はない．


## システム概要
以下の構成を対象する．
名付けは理解・区別しやすいように`ubuntu_cups`, `docker_cups`などとするが，実際は`cups`に統一するなどした方がよい．

* ubuntu Server上のDockerにcupsサーバを構築
    * ServerなのでCLIしか持たない．
        * Server上のDockerについては[こちら](https://qiita.com/NeK/items/d9431d5cdfa16dffe6dc)．
* cupsの設定はブラウザ経由と`lpadmin`(CLI経由)があるが，`lpadmin`を対象
    * ブラウザ経由は説明書き・自動化が面倒だから
    * Docker上のcupsだとブラウザ経由では面倒そうだから
    * ブラウザ経由は動作確認と設定確認くらいに使用
* プリンタプロトコル
    * 使用するプロトコル
        * lpd
            * ippがメジャーだけど勉強~~が面倒~~不足だから
* クライアント
    * 以下のネットワーク内にあるPCからアクセスすることを考える
        * 192.168.0.0/24

### ubuntu server情報
例として使用するサーバ情報

* FQDN
    * ubuntu_cups.mylab.ac.jp
* IP
    * 192.168.0.1/24
* Dockerfile関係のディレクトリ
    * ~/Docker
        * Dockerfile
        * docker-compose.yml
        * ~/drivers/
            * ***.debや ***.ppdファイル置き場
                * それぞれのプリンタに合わせて準備
                * 例としてprinter2.deb(192.168.0.2)とprinter3.ppd(192.168.0.3)を使用
                * 使用するプリンタに合わせて事前に準備
            * printer2.debについて
                * インストールが必要(dpkg)
                * インストール後の`lpadmin`での登録方法はプリント毎に調査
                * printer2.debの例
                    * `dpkg -i printer2.deb`
                    * `lpadmin -p printer2 -L "場所" -v lpd://PRINTER/BINARY_P1`
                        * 普通インストール後`lpinfo -v`で出てくる？
            * printer3.ppdについて
                * `lpadmin -p printer3 -L "場所" -v lpd://192.168.0.3/8080 -P /root/drivers/printer3.ppd`
                    * ppdファイルの場所が「/root/drivers/」になっているのはDockerfileの中で`COPY ./drivers /root/drivers`とするため
    * ~/bin/cups_settings/
        * `add_printer.sh`
            * `lpadmin`を毎回実行するのが面倒なのでシェル化

### docker情報
例として使用するdocker関係情報

* イメージ名
    * nek/cups:latest
* コンテナ名
    * docker_cups

# cups on Docker構築
## プリンタ関係ファイルの準備
deb, ppdファイルの準備して，以下のディレクトリに入れる．

* ~/Docker/drivers

## プリンタ登録用のスクリプト準備
スクリプトにしなくても良いが，手入力より楽なのと，プリンタの追加・削除をスクリプトで管理できるのでおすすめ．

```sh:~/bin/cups_setting/add_printer.sh
#!/bin/bash
/usr/sbin/lpadmin -p printer2 -E -L "場所1" -v lpd://PRINTER/BINARY_P1
/usr/sbin/lpadmin -p printer3 -E -L "場所2" -v lpd://192.168.0.3/8080 -P /root/drivers/printer3.ppd
/usr/sbin/lpadmin -d printer2 # printer2をデフォルトプリンタにする場合
```

## Dockerイメージの作成
### Dockerfileの準備

```dockerfile:~/Docker/Dockerfile
FROM ubuntu:22.04

COPY ./drivers /root/drivers

# cupsインストールなど
RUN set -x && \
    apt update && apt upgrade -y && \
    apt install cups -y

# cups基本設定
RUN sed -i 's!Listen localhost:631!Listen \*:631!' /etc/cups/cupsd.conf && \
    echo "ServerAlias ubuntu_cups.mylab.ac.jp" >> /etc/cups/cupsd.conf && \
    sed -i 's!BrowseLocalProtocols dnssd!BrowseLocalProtocols all!' /etc/cups/cupsd.conf && \
    sed -i 's!<Location />!<Location />\n  Allow 192.168.0.0/24!' /etc/cups/cupsd.conf && \
    sed -i 's!<Location /admin>!<Location /admin>\n  Allow 192.168.0.0/24!' /etc/cups/cupsd.conf && \
    sed -i 's!<Location /admin/conf>!<Location /admin/conf>\n  Allow 192.168.0.0/24!' /etc/cups/cupsd.conf

# cupsを使用するための設定やプリンタドライバのインストール
# /var/sppl/lpdは無いと怒られたため
RUN mkdir -p /var/spool/lpd && \
    dpkg -i /root/drivers/printer2.deb

CMD ["/usr/sbin/cupsd", "-f"]
```

### Dockerイメージ作成

```bash
cd ~/Docker
docker image build -t nek/cups:latest .
```

### docker-compose.ymlの準備

```yaml:docker-compose.yml
version: '3.9'

services:
  cups:
    image: nek/cups:latest
    container_name: docker_cups
    ports:
      - 515:515
      - 631:631
    restart: always
    volumes:
      - ~/bin/cups_settings:/root/bin/cups_settings:ro
```

### イメージ起動・追加設定

```bash
docker compose up -d
docker container exec -it docker_cups bash
# dockerコンテナにログイン・コンテナ内での作業となる．
/root/bin/cups_settings/add_printers.sh
exit
# dockerコンテナ内からのログアウト・ホストでの作業となる．
docker container commit docker_cups nek/cups:latest
```

# 通常利用
最後の`commit`で利用可能・すでに利用中となる．ブラウザ経由で`http://ubuntu_cups.mylab.ac.jp:631`にアクセスして管理画面が見えることを確認する．

## 以後

`docker compose down`で終了(コンテナも削除)，`docker compose up -d`でバックグラウンドで実行となる．
`restart: always`としているので，ホストを再起動しても自動的に起動する．

### lpadminとprinter.conf
lpadminがprinter.confを作るだけなら，/etc/cups/をvolumeマウントしてしまえばいい．もし気が向いたら更新．


# 総評
cupsの場合，docker使わずそのままインストール・使用でいいや．
インストールも簡単，設定も簡単．特にcupsd.confの編集はDockerfileを作成するためにsedを使用している．同じようにスクリプトにして保存しておけば問題ない．Dockerfileを保存するのか，設定用のスクリプトを保存するのかの違い．特にDockerの場合，`lpadmin`の問題からプリンタ設定用のスクリプトを作成・保存しているので，面倒くささは変わりない．

普通利用とdocker利用で利便さがそれほど異ならない(むしろdockerの方が手間がかかる場合あり)ので，実際は実機運用でいいかな．ただdockerの勉強以としては適していた．あとは，Docker swarm使えるようになると違うかも．

[当研究室のシステム]:https://qiita.com/NeK/items/70f994b271b0c1a48590
[cupsサーバ on Ubuntu Server]:https://qiita.com/NeK/items/ddbc1c00065e487777ed
[Dockerfile RUN lpadmin to add a printer not working in the built image?]:https://stackoverflow.com/questions/49503382/dockerfile-run-lpadmin-to-add-a-printer-not-working-in-the-built-image