公式サイトの英語版のほうに記事が出ている。9月25日づけ。
日本語のページにはまだない。
takatoh's blog – Learning programming languages.
公式サイトの英語版のほうに記事が出ている。9月25日づけ。
日本語のページにはまだない。
はてさて、前の記事からもうひと月も経ってしまった。
その、ひと月まえの記事に書いた、Ruby 用の ISBN を操作するライブラリを RubyGems.org にリリースした。名前は petrarca。
最初のリリース(v0.2.0)が8月30日で、その後バージョンアップして現在は v0.4.0(9月8日)。とりあえず自分では満足しているので、しばらくは大きな更新はないはず。
他のライブラリにはない(ざっと調べた限りではなさそうな)機能としては、ハイフン無しの ISBN をハイフンつきに変換する Petrarca.hyphenate メソッドが日本だけでなく世界中の ISBN に対応していること。こんな感じ。
irb(main):001:0> Petrarca.hyphenate("9780061052811") => "978-0-06-105281-1"
国や出版社の番号はそれぞれで桁数が違うわけだけど、International ISBN Agency のページから xml ファイルでダウンロードできるのでそれを利用している。このデータはときどき更新されるらしいので、バージョンアップするとしたらその対応だな。
大発明じゃなくて再発明、な。
ISBN を操作するための Ruby のライブラリを作った。
ISBN (International Standard Book Number)っていうのは、Wikipedia によると、図書の識別に使われる国際規格コードで、日本語では「国際標準図書番号」という。
別に新しいものでもなく、Ruby 用のライブラリも RubyGems.org で検索すればすでにいくつも存在することがわかる。チェックディジットのアルゴリズムも簡単だし、ちょっとやってみるのにはお手軽なのかも。そのせいかどうかは知らないけど、どのライブラリ(gem)をみても俺のニーズとずれている(約30分の調査による)。要するに気に入らない。俺のほしいのは:
が簡潔にできる機能であって、こういうのはモジュール関数でやればいいんだよ。わざわざ ISBN クラスなんて作る必要ないんだ。
というわけで、RubyGems.org に登録されてないのも含めると何百回目だか何千回目だかわからない車輪の再発明をしたわけだ。コードは GitHub に上げてある。
で、せっかく作ったんだから RubyGems.org にも上げておこう(みんなそう思ったんだろうな)として rake release
したら「そっくりな名前の gem がすでにあるんやで」みたいなメッセージが出て拒否された。一応、既存の gem とはかぶらないことを確認して isbn_utils っていう名前にしたんだけど、似ているだけでもダメみたいだ。そうなのか。知らなかった。
そういうわけなので、とりあえず RubyGems.org での公開は保留。いい名前が思いついたら再チャレンジする。かも。
Windows の Excel で、CSV ファイルに UTF-8 で出力ができることを知った。調べてみると結構前からできるようになってたようだ。
Excel で作ったデータを CSV ファイルに出力して Python のスクリプトで処理する、っていうのを時々やるんだけど、今まではいったん Shift JIS で出力したのを秀丸エディタを使って UTF-8 に変換してから処理していた。スクリプトは Linux でも使うから入力データのエンコーディングは UTF-8 にしておきたいんだよね。
で、Excel が UTF-8 の CSV をはいてくれるなら面倒な変換の手間を省いてそのままスクリプトで処理できる……と思ってやってみたらエラーになった。BOM(バイトオーダーマーク)がついているのが原因らしい。UTF-8 に BOM がついてるのとついてないのがあるのは知ってたけど、気にしたことはなかった。今回初めて BOM つきの UTF-8 に出くわした。軽くググってみると Windows だけが BOM をつけるらしい。
さて、本題。
Python で BOM つきの UTF-8 を読み込むには、ファイルを開くときのエンコーディングに utf-8-sig
を指定してやればいい。↓こんな感じ。
>>> import csv >>> with open('data_with_bom.csv', encoding='utf-8-sig') as f: ... for row in csv.reader(f): ... if row[0]: ... print(row[0]) ...
utf-8-sig
というエンコーディングは BOM なしの UTF-8 も扱える。なので UTF-8 であることがわかっていれば BOM を気にしなくていい。
>>> with open('data_without_bom.csv', encoding='utf-8-sig') as f: ... for row in csv.reader(f): ... if row[0]: ... print(row[0]) ...
というわけで、解決。
コード中に if row[0]:
とあるのは Excel のはいた CSV ファイルの後ろのほうにカンマだけの行がくっついてるからそれを避けるため。なんでそんな行がくっつくのかは謎。
っていうか Python って後置の if
が使えないんだね。ちょっと使いにくいな。
昨日、今日と2日続けて停電が発生した。午後に降った雷雨のせいだ(たぶん)。停電は短時間(1分もない)だったけど断続的に発生して、おかげで普段つけっぱなしの PC の電源が落ちた。サーバにしている PC も、だ。
雨がおさまってきたころ、PC の電源を入れて立ち上げたけど、サーバ PC で動かしている web アプリにアクセスしても繋がらなくなっていた。どうも IP アドレスが変わってしまったようだ。停電でルータの電源も落ちたからだな(たぶん)。
たいていの家庭のネットワークも同じだと思うけど、ウチのネットワークもルータの DHCP 機能を利用して各 PC に自動で IP アドレスを割り当てている。今回、ルータの電源も落ちたことで、PC を立ち上げたときに割り当てられたアドレスが変わってしまったらしい。
で、リモートではつながらないのでローカルにログインして、割り当てられている IP アドレスを確認して、hosts ファイルを修正したら繋がるようになった。
さて、もしかすると明日も雷雨で停電するかもしれないし、それでまた IP アドレスが変わってしまうようなことになればまた今日と同じ作業をしなくちゃいけなくなる。そんなのは面倒なので、DHCP で割り当てられる IP アドレスを固定にすることにした。
ルータは web インターフェイスで設定できるので、ログインしたら DHCP の設定のページで固定割り当ての設定をする。もう少し詳しく書くと、PC の NIC の MAC アドレスと、割り当てたい IP アドレスの組を登録しておくってことだ。PC が何十台もあるわけじゃないから大した作業ではない。
ともあれ、これで電源が落ちても今日みたいな作業をしなくても済むはずだ。もっと早くやっときゃよかった。
今日、久しぶりに GitHub にアクセスしたら、自分のプロファイルの下のところに「Arctic Code Vault Contributor」なる文字があるに気がついた。
何かと思って調べてみると、GitHub のリポジトリのソースコードを北極圏の島にアーカイブして1000年後まで保管するとかいう計画に選ばれたらしい。
「GitHub Arctic Code Vault」というプロジェクトに一環で、北極圏にあるノルウェーのスヴァールバル諸島の永久凍土の地下(廃坑)のなかにマイクロフィルムに保存されたソースコード(2020年2月2日に取得したスナップショット)を保存するというものだ。今回は第1回目で、頻度は明らかにされていないものの数年に一度くらいの割合でスナップショットを保存するらしい。
それにしても、オレの書いたソースコードが1000年先まで残るのか。スゲー。
……と思いながらよく読むと、アクティブなパブリックリポジトリはすべて対象になったようだ。オレの書いたコードなんて自分でしか使わないようなのばっかなんだけど、そういうことね。いや、それにしてもすごいけど。
ところで、今回保存されたソースコードの総量は約21TBとのこと。圧縮してるのかもしれないけど、以外に少ないと感じた。まぁ、ソースコードってほとんどはテキストファイルだからそんなものなのかな。
驚きのニュースが飛び込んできた。Perl が約25年ぶりのメジャーバージョンアップだと。
どのくらい驚いたかって、Perl の記事がほとんどないこのブログにも書いちゃうくらい驚いた。
とりあえず記録として残しておく。
GitHub のリポジトリにあるドキュメントを見ながら。
まずは GitHub から clone
。
takatoh@apostrophe:~$ git clone https://github.com/nodenv/nodenv.git ~/.nodenv
オプション扱いだけど dynamic bash extension とかいうのをビルド。nodenv がスピードアップするらしい。
takatoh@apostrophe:~$ cd ~/.nodenv && src/configure && make -C src
環境変数 PATH に ~/.nodenv を追加してから、セットアップ。
takatoh@apostrophe:~$ ~/.nodenv/bin/nodenv init Load nodenv automatically by appending the following to ~/.bashrc: eval "$(nodenv init -)"
メッセージにあるとおり、.bashrc に記述を追加。終わったらシェルを起動し直す。
nodenv-doctor
スクリプトで、ちゃんとインストールできてるか確認。
takatoh@apostrophe:~$ curl -fsSL https://github.com/nodenv/nodenv-installer/raw/master/bin/nodenv-doctor | bash
OK って出たから大丈夫なんだろう。
つぎに、これもオプションみたいだけど、node-build
をインストール。
takatoh@apostrophe:~$ mkdir -p "$(nodenv root)"/plugins takatoh@apostrophe:~$ git clone https://github.com/nodenv/node-build.git "$(nodenv root)"/plugins/node-build
これで完了。
nodenv install -l
でインストール可能な Node.js のバージョン一覧が見られる。公式サイトによると 12.18.1 が最新の推奨版なので、それをインストールする。
takatoh@apostrophe:~$ nodenv install 12.18.1
nodenv global
で利用するバージョンを指定。
takatoh@apostrophe:~$ nodenv global 12.18.1
これで最新推奨版の Node.js が使えるようになる。
takatoh@apostrophe:~$ node --version v10.19.0
えっ??
takatoh@apostrophe:~$ nodenv versions system * 12.18.1 (set by /home/takatoh/.nodenv/version)
ちゃんと 12.18.1 になってるじゃないか。どういうこと?
ちょっとびっくりしたけど、なんのことはない、シェルを立ち上げ直したらできた。
takatoh@apostrophe:~$ node -v v12.18.1
おしまい。
前回の記事では、Docker のネットワークを使って通信しながら、複数のコンテナを協働させた。
基本的には前回の記事のやり方でいいんだけど、サービスの数が増えたり、規模が大きくなってコンテナの数が増えたりすると、コンテナごとにコマンドを打って起動するのは面倒だ。コンテナによって指定するオプションも異なるので、それも覚えておく必要がある。
というわけで、そういう煩雑な部分を楽にしてくれるツールがある。それが Docker Compose だ。メインマシンである apostrophe をセットアップしたときに apt でインストールしておいた。
akatoh@apostrophe:docker$ docker-compose --version docker-compose version 1.25.0, build unknown
前回記事と同じ、書籍管理 web アプリと HTTP サーバ(Nginx)という構成にする。詳しくは前回記事を参照。
前回ビルドした Docker イメージが残っているので、まずはそれを使ってコンテナを起動する設定を書いてみる。
Docker Compose は docker-compose.yml という名前のファイルを読み込んで、その設定どおりにコンテナを起動してくれる。今回書いた docker-compose.yml ファイルは次の通り。
version: '3' services: bruschetta-back: image: bruschetta:1 container_name: bruschetta-back restart: always nginx-front: image: nginx-c:1 container_name: nginx-front restart: always ports: - 8080:80
service: の下に連なっているのが、Docker Compose で起動するコンテナだ。各設定項目は見ればだいたいわかるだろうからここでは説明は省略。ただ、docker
コマンドで起動するときとは次の点が違う。
特に2つ目の挙動は docker
コマンドで起動したときと違うので注意が必要だ。最初、ここでハマった。
で、これを起動するには次のようにする。
takatoh@apostrophe:docker$ docker-compose up -d
起動中のコンテナの確認。
takatoh@apostrophe:docker$ docker-compose ps
そして停止。
takatoh@apostrophe:docker$ docker-compose stop
最後にコンテナの削除。
takatoh@apostrophe:docker$ docker-compose rm
さて、今度は Docker イメージをビルドするところからやってみる。そのためには、docker-compose.yml ファイルと同じディレクトリに、イメージ作成用のファイル一式を収めたディレクトリを置いておく。こんな感じ。
akatoh@apostrophe:docker$ ls -l 合計 12 drwxrwxr-x 3 takatoh takatoh 4096 5月 9 03:15 bruschetta -rw-rw-r-- 1 takatoh takatoh 239 6月 14 13:26 docker-compose.yml drwxrwxr-x 3 takatoh takatoh 4096 5月 14 06:19 nginx-c
そして、docker-compose.yml ファイルを次のように書き変える。
version: '3' services: bruschetta-back: build: ./bruschetta image: bruschetta:1 container_name: bruschetta-back restart: always nginx-front: build: ./nginx-c image: nginx-c:1 container_name: nginx-front restart: always ports: - 8080:80
書き変えた、というか書き足したのは、build:
の行だ。この行でイメージをビルドするための Dockerfile (とその他に必要なフィアル)を置いてあるディレクトリを指定している。
ビルドするには次のようにする。
takatoh@apostrophe:docker$ docker-compose build
イメージができたか、確認。
takatoh@apostrophe:docker$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE nginx-c 1 c8b3966bbc31 54 seconds ago 127MB bruschetta 1 7d6607e796c2 About a minute ago 468MB nginx 1.17.10 9beeba249f3e 4 weeks ago 127MB ubuntu 20.04 1d622ef86b13 7 weeks ago 73.9MB
nginx-c:1 と bruschetta:1 がビルドされたイメージ。下の2つは元になったイメージ(Docker Hub から取ってきたもの)だ。
じゃあ、これを起動してみよう。
takatoh@apostrophe:docker$ docker-compose up -d
OK。ブラウザからアクセスしてみて、期待通りに動いているのを確認できた。
Docker を使ったサービスでは、サービスを構成する各サーバプログラムをそれぞれ別のコンテナで立ち上げるのが一般的なようだ。例えばデータベース(MySQLなど)を利用する web アプリケーションであれば、つぎの3つのコンテナを立ち上げることになる:
当然、これらを連携するにはコンテナ間をまたいだ通信をする必要がある。Docker にはコンテナ間通信を実現するネットワーク機能が備わっていて、各コンテナは同じ(Docker の)ネットワークに接続していれば、コンテナ名とポート番号を使って通信することができる。
今日はそのコンテナ間通信を試してみる。
先日作った書籍管理 web アプリと、HTTP サーバとして Nginx を前に立てる構成とする。上にはデータベースサーバが書いてあるけど、この書籍管理アプリはデータベースに Sqlite を使っているので、今回データベースサーバはなし。アプリケーションサーバと HTTP サーバ(Nginx)の2つだ。
コンテナ名は、アプリケーションサーバを bruschetta-back、HTTP サーバを nginx-c とする。この2つが Docker ネットワークで通信するわけだ。nginx-c は80番ポートをホスト側の8080ポートに接続する。ホスト側からは bruschetta-d というホスト名で nginx-c にアクセスできるようにしておく。
先日作ったものなので詳細は省略。ただ、あいだに PC のリプレイスをはさんだので、イメージ名が bruschetta:1 に変わっている。内容は変更なし。
全面に立てる HTTP サーバには、Docker Hub で公開されている Nginx こイメージをメースにして、アプリケーションサーバにつなぐための設定ファイルをコピーしたものを用意する。
Dockerfile はこう:
ROM nginx:1.17.10 COPY ./files/bruschetta-d /etc/nginx/conf.d/bruschetta-d.conf RUN mkdir /var/log/nginx/bruschetta CMD [ "nginx", "-g", "daemon off;" ]
この中でコピーしている Nginx の仮想ホストの設定ファイルはこうだ:
upstream uwsgi-bruschetta { server bruschetta-back:5000; } server { # port listen 80; # server name server_name bruschetta-d; # log files access_log /var/log/nginx/bruschetta/access.log combined; error_log /var/log/nginx/bruschetta/error.log warn; keepalive_timeout 60; proxy_connect_timeout 60; proxy_read_timeout 60; proxy_send_timeout 60; location / { proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_pass http://uwsgi-bruschetta; } }
これで docker build
した。
できたイメージの状況。
akatoh@apostrophe:docker$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE nginx-c 1 6f5be529ea6d About a minute ago 127MB bruschetta 1 11afb91367ae 2 hours ago 451MB nginx 1.17.10 9beeba249f3e 8 hours ago 127MB ubuntu 20.04 1d622ef86b13 3 weeks ago 73.9MB
Docker ネットワークの作成は docker network create
コマンドを利用する。
takatoh@apostrophe:docker$ docker network create nginx-network
これで nginx-network という名前の Docker ネットワークができた。つぎのようにすると様子が見える。
takatoh@apostrophe:docker$ docker network ls NETWORK ID NAME DRIVER SCOPE d0c23099f6be bridge bridge local 492e64e5d79d host host local 7f38bac647a0 nginx-network bridge local b42cbd843632 none null local
nginx-network 当名前が見える。ほかにもあるけど、これらはデフォルトで用意されているものらしい。詳細は調べてない。
2つのコンテナを起動する。その際、--netowork
オプションで接続する Docker ネットワークの名前(今回は nginx-network)を指定する。また、HTTP サーバのコンテナの方でアプリケーションサーバの名前を bruschetta-back と指定しているので、これを間違えないようにする。
まずはアプリケーションサーバのコンテナから。
takatoh@apostrophe:docker$ docker run --name bruschetta-back --network nginx-network -d bruschetta:1
HTTP サーバ。ポートの指定も忘れずに。
akatoh@apostrophe:docker$ docker run --name nginx-front --network nginx-network -p 8080:80 -d nginx-c:1
起動したコンテナは bruschetta-d というホスト名で待ち受けているので、/etc/hosts ファイルに 127.0.0.1 を指すように記述を追加する。それができたら準備は完了だ。http://bruschetta-d:8080/ にブラウザでアクセスしてみる。
結果、期待通りにアプリケーションにアクセス、使用できることが確認できた。