Jaybanuan's Blog

どうせまた調べるハメになることをメモしていくブログ

Docker ComposeのComposeファイルのバージョンについて

はじめに

Docker ComposeのComposeファイル(docker-compose.yml)の冒頭でversion: '3'のようにバージョン表記があるが、バージョン番号に何を書くのが正しいかを調べてみた。

結論

Composeファイル中のversionで指定するのは、Composeファイルのフォーマットのバージョンである。 公式ドキュメントとGitHubのreleaseの情報をまとめると、各バージョンの対応表は以下の通り。

Compose file format Docker Engine
3.7 (Compose 1.22.0+) 18.06.0+
3.6 (Compose 1.20.0+) 18.02.0+
3.5 (Compose 1.18.0+) 17.12.0+
3.4 (Compose 1.17.0+) 17.09.0+
3.3 (Compose 1.14.0+) 17.06.0+
3.2 (Compose 1.12.0+) 17.04.0+
3.1 (Compose 1.11.0+) 1.13.1+
3.0 (Compose 1.10.0+) 1.13.0+
2.4 (Compose 1.21.0+) 17.12.0+
2.3 (Compose 1.16.0+) 17.06.0+
2.2 (Compose 1.13.0+) 1.13.0+
2.1 (Compose 1.9.0+) 1.12.0+
2.0 (Compose 1.6.0+) 1.10.0+
1.0 1.9.1.+

フォーマットのバージョン2.xと3.xは並行してアップデートされているようだ。 それぞれのバージョンのフォーマットのドキュメントは、以下にある。

Compose file format ドキュメントのURL
3.x https://docs.docker.com/compose/compose-file/
2.x https://docs.docker.com/compose/compose-file/compose-file-v2/
1.0 https://docs.docker.com/compose/compose-file/compose-file-v1/

Composeファイルのバージョンの指定方法について

ドキュメントには以下のようにある。

Note: When specifying the Compose file version to use, make sure to specify both the major and minor numbers. If no minor version is given, 0 is used by default and not the latest minor version.

日本語に訳すと以下のようになる。

注: 利用時にComposeファイルのバージョンを指定する場合は、メジャーとマイナーの番号を確実に指定してください。もしマイナーバージョンの指定がない場合は、最新のマイナーバージョンではなく、0が利用されます。

なので、明確にversion: '3.7'のように書くべきで、version: '3'という指定方法は避けたほうが良い。 公式ドキュメント中のサンプルのdocker-compose.ymlには、後者の表記が用いられていることがあるので、サンプルを流用する場合は注意が必要。

参考

systemdにおける/etc/sysconfigと/etc/default

はじめに

systemdのユニットファイルを調べた際に、/etc/sysconfig/etc/defaultについても調べたので、メモを残しておく。

/etc/sysconfigと/etc/default

ディレクトリとも、SysV initのスクリプトの設定ファイルをおいておく場所。 /etc/sysconfigRedHat(Fedora)系で利用されており、/etc/defaultDebian系で利用されている。

systemdの視点から

systemdの開発者のLennart Poetteringさんの以下のブログから掻い摘むと、「これらのディレクトリはSysV init用のレガシーなもので使うべきじゃないし、systemdのドロップインの仕組みを使えば事足りるよね」と言っているようだ。

「ドロップイン」とは、/etc/systemd/system/[サービス名].service.dというディレクトリの中に.confファイルを入れておけば、自動的に読み込んでくれる仕組みのこと。

参考

systemdのユニットファイルをテンプレート化する

はじめに

複数のサービスを自作してsystemdで管理するときに、作成するユニットファイルの中身が大体同じということがある。 こういう場合はユニットファイルのテンプレート化が有効なので、そのやり方をメモしておく。 動作確認は簡単にしたいので、ここではWebサーバのポート番号を変数化したユニットファイルを作成することにした。

環境

$ cat /etc/os-release | grep PRETTY_NAME
PRETTY_NAME="Ubuntu 18.04.4 LTS"

$ python3 --version
Python 3.6.9

事前準備

いろいろWebサーバを探してみたものの、ポート番号を引数に渡して起動できる手頃なWebサーバが見当たらなかったので、自前で作成することにした。 まずは、以下の内容で/opt/test-web-server/test-web-server.pyを作成する。

#!/usr/bin/env python3

from sys import argv
from http.server import BaseHTTPRequestHandler
from http.server import HTTPServer

class ServerAddressHandler(BaseHTTPRequestHandler):

    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/plain')
        self.end_headers()

        text = 'server_address = ' + str(self.server.server_address) + '\r\n'
        self.wfile.write(text.encode('utf-8'))


if __name__ == '__main__':
    port = int(argv[1])

    httpd = HTTPServer(('0.0.0.0', port), ServerAddressHandler)
    httpd.serve_forever()

このファイルに実行権限をつけておく。

$ chmod a+x /opt/test-web-server/test-web-server.py

動作確認のために、待受ポートの10080を引数に指定して、このWebサーバを起動する。

$ /opt/test-web-server/test-web-server.py 10080

別のターミナルからcurlでWebサーバにアクセスすると、待ち受けているIPアドレスとポート番号を取得できる。

$ curl http://localhost:10080
server_address = ('0.0.0.0', 10080)

これで事前準備は完了。 起動したWebサーバを停止しておく。

ユニットファイルの作成と、ひとつめのサービスの登録

次の内容でファイル/etc/systemd/system/test-web-server@.serviceを作成する。

[Unit]
Description=Test Web Server with port %i

[Service]
Type=simple
ExecStart=/opt/test-web-server/test-web-server.py %i

[Install]
WantedBy=multi-user.target

具体化されたサービスの作成方法は、コマンドラインを見た方が分かりやすい。 例えば、ポート番号10080で待ち受けるサービスを登録するには以下のようにする。

$ sudo systemctl enable --now test-web-server@10080
Created symlink /etc/systemd/system/multi-user.target.wants/test-web-server@10080.service → /etc/systemd/system/test-web-server@.service.

つまり、ユニットファイルのファイル名、すなわちサービス名の@以降が変数%iに割り当てられる。 ここで登録したサービスの状態を確認するには、同様にサービス名の@以降に10080を指定してsystemctl statusを実行すればよい。

$ systemctl status test-web-server@10080
● test-web-server@10080.service - Test Web Server with port 10080
   Loaded: loaded (/etc/systemd/system/test-web-server@.service; indirect; vendor preset: enabled)
   Active: active (running) since Sat 2020-02-08 17:29:13 JST; 5min ago
 Main PID: 4632 (python3)
    Tasks: 1 (limit: 4637)
   CGroup: /system.slice/system-test\x2dweb\x2dserver.slice/test-web-server@10080.service
           └─4632 python3 /opt/test-web-server/test-web-server.py 10080

 2月 08 17:29:13 ubuntu1804 systemd[1]: Started Test Web Server with port 10080.

想定通り%i10080に置き換わっていることが分かる。 では、curlを実行してWebサーバの動作確認をしてみる。

$ curl http://localhost:10080
server_address = ('0.0.0.0', 10080)

事前準備の時と同様に、待ち受けているIPアドレスとポート番号が正しく表示された。

ふたつめのサービスの登録

次はポート番号20080で待ち受ける、ふたつめのサービスを登録してみる。

$ sudo systemctl enable --now test-web-server@20080
Created symlink /etc/systemd/system/multi-user.target.wants/test-web-server@20080.service → /etc/systemd/system/test-web-server@.service.

確認のため、名前がtest-web-server@から始まるサービスをリストする。

$ systemctl list-units -t service 'test-web-server@*'
UNIT                          LOAD   ACTIVE SUB     DESCRIPTION                    
test-web-server@10080.service loaded active running Test Web Server with port 10080
test-web-server@20080.service loaded active running Test Web Server with port 20080

(以下略)

想定通り、ポート番号が10080のサービスと20080のサービスが表示されている。 では、curlを実行してWebサーバの動作確認をしてみる。

$ curl http://localhost:10080
server_address = ('0.0.0.0', 10080)

$ curl http://localhost:20080
server_address = ('0.0.0.0', 20080)

ポート番号が10080のWebサーバも、20080のWebサーバも正しく動作していることが分かる。

参考

OSSの運用とライセンスについての情報源

はじめに

OSS運用のスタッフ的視点での情報減を少しずつまとめていく。 あとは、ライセンスやリーガルなことも。

とりあえずこれ

IPAが提供している情報

License

Contributor Agreements

wmctrlを利用したウィンドウのリサイズ

はじめに

とあるドキュメントの作成の都合上、Linuxでウィンドウのスクリーンショットを取る必要に迫られた。 ドキュメントのレイアウトの崩れを防ぐために、ウィンドウのサイズは統一しておきたかった。 そのためウィンドウを思い通りにリサイズできるコマンドを探してみた。 どうもwmctrlを使えばよいらしい。

使い方

まずウィンドウのリストを表示する。

$ wmctrl -l
0x0140000a  0 devpc デスクトップ
0x02800001  0 devpc Google - Google Chrome
0x02200003  0 devpc Mozilla Firefox
0x03a00006  0 devpc redj@devpc: ~
0x03c00001  0 devpc Untitled-1 - Visual Studio Code

表示される行のフォーマットは以下。

[ウィンドウID] [デスクトップ番号] [Xクライアントのホスト名] [ウィンドウタイトル]

例えば、座標(100, 100)を起点に、幅1280、高さ800でリサイズする場合は以下のようにする。 ここでは、対象のウィンドウはウィンドウタイトルで指定する。オプション-eのフォーマットはgravity,起点x,起点y,幅,高さで、gravityには通常は0を指定しておく。

wmctrl -r "Google - Google Chrome" -e 0,100,100,1280,800

また、ウィンドウIDを指定してリサイズする場合は、上記のコマンドラインのオプションに-iを加えて、以下のようにする。

wmctrl -i -r 0x02800001 -e 0,100,100,1280,800

参考

static int window_move_resize (Display *disp, Window win, char *arg) {
    // (略)

    if (wm_supports(disp, "_NET_MOVERESIZE_WINDOW")){
        return client_msg(disp, win, "_NET_MOVERESIZE_WINDOW", 
            grflags, (unsigned long)x, (unsigned long)y, (unsigned long)w, (unsigned long)h);
    }

    // 略

Jinja2のhello, world!

はじめに

JInja2のドキュメントの最初のサンプルコードが分かりにくくて、しばらくぶりだと色々調べ直しになる。。。 なので、最小限のコードを備忘録として残しておく。

環境

Ubuntu 18.04LTS

Jinja2のインストール

# pip3 install jinja2

hello, world!

以下の内容でgreeting.pyを作成する。

import jinja2

# create Jinja2 Environment
env = jinja2.Environment(loader = jinja2.FileSystemLoader('./'))

# load template
template = env.get_template('template.txt.j2')

# rendering
context = { 'name': 'world' }
result = template.render(context)

# print "hello, world!"
print(result)

以下の内容でtemplate.txt.j2を作成する。

hello, {{ name }}!

以下のように実行する。

$ python3 greeting.py 
hello, world!

参考

Pythonでリストからディクショナリを生成する

Pythonでキーとバリューが交互に並んだリストからディクショナリを生成するには、以下のようにする。

x = ['key1', 'value1', 'key2', 'value2']
y = dict(zip(x[0::2], x[1::2]))

まず、ステップ数を指定したスライスを利用して、x[0::2]でキーのリストを、x[1::2]でバリューのリストを生成する。 次に、zip()を利用してタプル(キー, バリュー)を要素に持つイテレータを生成する。 そして、そのイテレータを引数にしてdict()を呼び出し、ディクショナリを生成する。

ただし、キーの数とバリューの数が不揃いだった場合、zip()だと短い方に切り詰められるので、エラーハンドリングをしたいならばitertools.zip_longest()を活用する必要があるようだ。

参考