u-ryo's blog

various information for coding...

Category: Docker

Markdown to Pdf on CLI

| Comments

markdownで快調に書いたものを、「印刷して提出せよ」ということになっていたので、「へ?」とか思って。今時ねぇ、印刷なんてねぇ、何の意味があるのか。一応evidenceってことなんだろうけど。

調べると、意外とないんですよね日本語markdown to pdf。popularなのはMS Visual Studio Codeの拡張機能Markdown PDF使うものですけど、たったそれだけのためにVisual Studio Code入れたかぁないですし。 nodeのmarkdown-pdfmd-to-pdfとかサクッと出来そうだったんですけど、古いのか、どうしようもないエラーが出ます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
docker run --rm -it -v $PWD:/work -w /work -e https_proxy=http://192.168.120.1:3128 node:alpine sh
# npm i -g markdown-pdf
# markdown-pdf some.md
node:events:497
      throw er; // Unhandled 'error' event
      ^

Error: spawn /usr/local/lib/node_modules/markdown-pdf/node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs ENOENT
  :
# npm i -g md-to-pdf
# md-to-pdf some.md
(node:29) [DEP0040] DeprecationWarning: The `punycode` module is deprecated. Please use a userland alternative instead.
(Use `node --trace-deprecation ...` to show where the warning was created)

  Puppeteer old Headless deprecation warning:
    :

  ✖ generating PDF from some.md
    → TROUBLESHOOTING: https://pptr.dev/troubleshooting
ListrError: Something went wrong
    at /usr/local/lib/node_modules/md-to-pdf/node_modules/listr/index.js:102:18
     :

pandocもいいんですが、texの環境色々入れるのがかったるいなー。 というわけで、docker baseで。 探すと、参考文献がありました。proxyも使わないとならないので。

1
2
3
4
5
6
7
8
9
10
$ PROXY=http://192.168.120.1:3128
$ docker run --rm -it -e https_proxy=$PROXY -e http_proxy=$PROXY -e ftp_proxy=$PROXY -e use_proxy=yes -v $PWD:/data --entrypoint sh pandoc/latex
/data # tlmgr install collection-langjapanese
   :
tlmgr: package repository ftp://tug.org/historic/systems/texlive/2022/tlnet-final (not verified: valid signature with expired key)
   :
[108/108, 22:16/22:16] install: collection-langjapanese [1k]
running mktexlsr ...
   :
/data # pandoc some.md -o some.pdf -C --pdf-engine=lualatex -V linkcolor=blue -V documentclass=ltjsarticle -V luatexjapresetoptions=fonts-noto-cjk
  • 何か今どきftpで取りに行くので、ftp_proxyが必要
  • use_proxy=yesもないとproxy経由と認識してくれなかった
  • working directoryはdefaultで/dataなのでそこにmountする
  • entrypointが入っているので、optionで上書きしないとtlmgrを動かせない
  • pandoc/coreではなくpandoc/latexであることに留意
    • 500MB超とsizeも結構ある
  • tlmgr install collection-langjapaneseは22分かかった
    • 総計30分弱はかかる
  • 基本的にはpandoc md_file -o pdf_fileだが、--pdf-enginelualatexを指定したりdocumentclassltjsarticleを指定したり、日本語特有の指定が必要
  • ###が本文と同じ大きさの文字になるので、思っているよりlevelを1段階上げとかないと、思ったような出力にならない

Ansible for Docker

| Comments

ansibleのlocalでの開発環境といえばvagrant+virtualboxですが、dockerでいいんじゃねぇの?と思って色々試行錯誤してみました。何度も挫けて、もう駄目かと思いましたけど、幾つもの山を越え、ついに出来ましたですよ!

docker.ini
1
2
3
4
5
[docker_host]
localhost

[container]
eiger-local
playbooks/docker.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
- hosts: localhost
  connection: local
  gather_facts: no
  vars:
    ansible_python_interpreter: /Users/ryo-umetsu/.anyenv/envs/pyenv/shims/python
    # ansible_python_interpreter: /usr/bin/python3
  tasks:
    - name: deploy amazonlinux docker
      docker_container:
        image: amazonlinux
        name: eiger-local
        volumes:
          - /sys/fs/cgroup:/sys/fs/cgroup:ro
        ports: 57017:27017
        expose: 57017
        tty: yes
        detach: yes
        privileged: yes
        # capabilities:
        #   - SYS_ADMIN
        # sysctl:
        #   vm.swappiness: 1
        command: sh -c 'yum -y install procps systemd-sysv file && exec /sbin/init && systemctl restart'
    - name: adding host
      add_host: name="eiger-local"
    - name: wait
      wait_for:
        delay: 10
        timeout: 10

- hosts: eiger-local
  connection: docker
  vars:
    setup_mongodb_password: !vault |
      $ANSIBLE_VAULT;1.1;AES256
          39356533306331333763353433363335343961653335373762623630653361623034646232633837
          6164306666656436653636643333363261646662356666640a636462346635323164633365376637
          39303832396638336664653439326536386235323262303733653563653766353263623032386538
          3135623166613363630a343734666666323830663838653962663032386337626635396563383230
          6266
    # setup_mongodb_password: "test"
    ansible_python_interpreter: /usr/bin/python
  roles:
    - role: "../roles/create_data_directory"
    - role: "../roles/setup_mongodb"
    - role: "../roles/configure_logrotate"
    - role: "../roles/configure_swap"

凄いknow-how詰まってます。

  • connection: localとするとssh経由じゃなく直接command叩いてくれる
  • connection: dockerとするとdocker execで叩いてくれる(のでtargetにauthorized_keysとかsshdとか不要)
  • localhostではgather_facts: noとする(これをしないとansible_swaptotal_mbとかansible_memtotal_mbといったシステムから検出される変数: Fact (ファクト)が埋められない)
  • ansible_python_interpreter: /usr/bin/python3python binaryを探す順序があって、/usr/bin/pythonを先に見つけてしまい、version 2を使ってしまうのを防ぐため。Macだと/usr/bin/pythonがpython2で、python3は/usr/bin/python3なので。ここのversionが合わないと、The error was: No module named 'requests'"と言われて何が悪いのかさっぱりだった。基本的にはpip3 install dockerが足りなかったのだが、その他に、このようにansibleが自分で見つけて使っているpythonのversionと自分がcommand lineで使っていてpip installしたpythonのversionがずれていると、このように言われる、ことがわかった。その他にもinventoryで指定することもcommand line optionで指定することも出来る。command line optionで-e ansible_python_interpreter=/usr/bin/python3とするのが最も柔軟だが、これはplaybooks中の値を全て上書きするので、やはり注意が必要だった。pythonってversionややこしくて...
  • setup_mongodb_password: !vault |Single Encrypted Variableecho -n test|ansible-vault encrypt_string --vault-password-file vault_password.txt --encrypt-vault-id default --stdin setup_mongodb_passwordのように使う(ansible-vaultで暗号化しよう。)
  • docker_container:はmodule名で、古い文献だとdocker:になっていて今は効かないので注意。中で指定できるものはcommunity.docker.docker_container – manage docker containersに挙がっている。privileged: yesは、container内でsysctl vm.swappiness=1(defaultは60)をされるので。sysctl:というoptionもあるのだけれど、そこで指定できる(whitelistにある)のはnet.*とかkernel.*の一部だけだそう(サポート中の sysctl)。
  • command: sh -c 'yum -y install procps systemd-sysv file && exec /sbin/init'は、playbook中でsystemctlを設定するものがあるから。Restart=alwaysにしたいんですよね要するに。でも、そうするとdockerにsystemd(initd)が動いていねばならず、そういえばdockerって普通はそんなのなかったな、どうやるんだ? 調べると、
  • systemd-sysvをinstallする必要
  • /sys/fs/cgroup:/sys/fs/cgroup:roのdevice mountが必要
    • macにはそんなdirectoryはないのに大丈夫なのが不思議
  • 最後は/sbin/init
  • ↑これではcontainerが数秒で倒れるので更に調べるとexec /sbin/init(これどこで見たんだっけなぁ感動したなぁStackOverflowだった気が。他では全然書いて無くて、よく見つけたもんだ)
  • wait_for:がないと、docker内にまだyum installとか終わりきってないのにどんどん次に進んでしまい、service.name:mongod,service.enabled:trueの時に「mongodというserviceはない」といって落ちてしまうので。ホントはちゃんと何かを待ちたかったんだけど、何を待ったらいいのか不明でした。processかなと思ったんですが、processのwaitってpid fileの存在有無を確認するみたいな。いゃー、systemdというかinitってpid fileなんてないんですけど。network port待つ例は数多あれど。仕方ないのでただ10秒待つように。timeout:10は不要かと思いきや、ないとずっと待ってました。
  • これをansible-playbook -vvv -i docker.ini playbooks/docker.ymlと実行するんですが、dockerでやる場合はansible/ansible-runner使って、docker run --rm --name=ansible -v $PWD:/work -w /work -v /var/run/docker.sock:/var/run/docker.sock ansible/ansible-runner sh -c 'pip3 install docker&yum install -y yum-utils;yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo;yum install -y docker-ce docker-ce-cli containerd.io;ansible-playbook -i docker.ini playbooks/docker.yml'と、CentOS8 baseのansible-runnerにdockerを入れねばならず、またunix socketを共有しないとなりませんでした。CentOS8にyum install dockerするとpodmanが入りやがるんですよね。podmanってMacじゃ動かねぇっつーの! podmanだとhosts:eiger-localgather_factsでDocker version checkに失敗して落ちるんですよね。Podman broken on Silverblue? Podman complains kernel not supporting overlay fs (backing file system is unsupported for this graph driver)見てsed -i "s/#mount_program/mount_program/" /etc/containers/storage.conf加えても、Error: mount /var/lib/containers/storage/overlay:/var/lib/containers/storage/overlay, flags: 0x1000: operation not permitted。うーん。逆に、docker containerにansibleを入れる方がsimpleでした。即ち、docker run --rm --name=ansible -v $PWD:/work -w /work -v /var/run/docker.sock:/var/run/docker.sock docker sh -c 'apk add ansible py3-pip;pip3 install docker;ansible-playbook -i docker.ini playbooks/docker.yml'ですね。

参考サイト

Arukas Cloud

| Comments

Sakuraがやっているからそのreverse spellingだというArukas、 docker hostingをやっていて、 credit card登録は強制されますが1 containerなら無料というので、 専用SSH machine作ってJHipsterの開発/buildに使おうと企みました。

無料枠ではDocker Hubにあるものしか使えないとはいえ、 SSH serverの入ったdocker imageなんて色々あります。 でも使ってみると、基本的にはrootでlogin、 当然root loginをpermitしていて、 securityを維持するにはrootのpasswordを変える、 userを作って.ssh/authorized_keysを作る、 とかなわけですが、けどroot loginのpermissionを切って sshdをrestartすると、docker終わっちゃうんですよね当たり前ですが。 何かもっとこう、最初からUser作ってrootは禁止して、 とかっていうの無いかなー、 と物色していると、どれだったか忘れましたがgithub.comから 自分が登録したkeyをADDしてるものがあって、 あーなるほどー、と思って。 ADD https://github.com/$GITHUB_USER.keys /home/$GITHUB_USER/.ssh/authorized_keysということですね。

で、結局どうしても自分の欲しいものがなかったので、 Dockerfile自作することにしました。 元になるimageはDocker Hub上になければいけないので、 Docker Hubを使ってGitHubにあるDockerfileからimageを自動生成するを参考に、 Github → Docker Hub → Arukasという流れになるように、 自分のGithub repository自分のDocker Hub repository自分のArukas App と繋げて、 回るようにします。

Arukasでは変数定義が出来るというのでDockerfileでGithub user名をENV定義して、 でもそうするとDocker HubではbuildにコケるのでENVには何かdefault値がないとダメで、 でもdefault値を付けちゃうとそのdefault値がArukas Appまで残っちゃうんですよね。 Docker コンテナの動作に必要な設定を起動時に渡すなどを見て、 え、shell script内じゃないとダメ? じゃぁっていうんでentrypoint.sh作って試してみたんですけど、 Arukasで起動に失敗しました。Docker Hubではbuild通ったのに。 Arukasでは起動時のmessageとかは出ないので、何が悪いのか分かりません。 困り果ててArukasのchatで相談投げると、翌営業日にはすぐreplyをくれて、 動作確認のためということでpull requestまで作ってくれました。 まずは早速そのまま取り込んで起動してみたんですが、 やはり起動に失敗。 けれども、別のaccountの方でENVを編集することで再起動させてみたところ うまく行ったので、何だったんでしょう? 結局今はどちらでも上手く立ち上がるようになりました。 ありがとうございました。

他、Arukasでハマったのは、開放するPort、 後で色々service立ち上げようと思って3000番とか8080番とか色々書いておいたら、 Endpointが有効にならないんですね。 これもArukasのchatで聞いて教えてもらったんですが、 確かによく読むと、「Docker image立ち上がった時点で 書いたPortが全て開いてないとEndpointが有効にならない」 と書いてありますね。 「一番上に書いたPortだけEndpointに繋がる」というのは 「アプリ編集」画面のEndpointのinfoに書いてあるからわかったんですが。

baseとなるdistributionは、 軽いというAlpine Linuxに。 アプリの管理もapk add ...コマンドで出来ますし、 packageもscreenやらopenjdk8やらgradleやら 結構色々あってびっくりです。 何かubuntuじゃなくてalpineで十分な気がしてきました。

目的としていたjhipster applicationのbuildは失敗しました。 specがしょぼい(128MB memory)のか通信量に制限があるのか、 jhipsterコマンドの途中で止まり、 applicationのscaffoldingが出来ません。 まー、無料枠なのでmachine specについては文句言えませんから、 しょーがないのかなーと。

ただ、Endpointがhttpsで手に入るので、 Nginxによるリバースプロキシの設定方法を参考に、 nginxによるreverse proxyとして使おうかなー、 と思っています。 custom domainも使えるとのことですが、 CDNと同じくDNSを自分でcontrol出来ねばならないので、 dynamic DNSでは使えず、custom domainは諦めました。

  • docker hubの成果物(といってもpull requestくれた山田さんのおかげモノですが。山田さんありがとうございます!)

Githubにkeyを登録してあれば、Arukas AppでImageにこれ↑を指定し、 ENVGITHUB_USERをGithubのuser名、 PROXY_PASSをreverse proxyしたいURL、 にして立ち上げると、 当該hostにssh出来、 またEndpointで指定したURLでreverse proxy出来ます。

1
2
ln -sf /dev/stdout /var/log/nginx/access.log
ln -sf /dev/stderr /var/log/nginx/error.log

こんな技があるんですねーなるほどー。