bookmark_border.devドメインと.appドメインがHTTPSを強制する仕組み

トップレベルドメインの中に.devと.appがある.これらはHTTPS接続を強制するドメインとして知られている.この仕組みが気になっていたので調べてみた.

参考: グーグル、完全HTTPS接続で安全なアプリ用ドメイン「.app」–早期登録を受付開始 – CNET Japan

仕組み

結論: HSTSPreload Listという技術を使っている.

HSTS

HSTS(HTTP Strict Transport Security)はHTTPでアクセスしてきたユーザ(HTTPクライアント)にHTTPSでのアクセスを強制するための技術である.対応しているWebサイトでは,HTTPレスポンスのヘッダに Strict-Transport-Security: xxx が付与されている.Qiitaの場合はstrict-transport-security: max-age=2592000が設定されている.RFC 6797で定義されている.

参考: Strict-Transport-Security – HTTP | MDN

FacebookはHSTS Preloadがレスポンスヘッダに含まれている.
image.png

Preload List

Preload ListはRFC 6797の中で定義されている.サイトの管理者は事前に定義したHSTSポリシーをpre-loaded listとよばれるリストにもたせることができる.このリストは,ブラウザがルート認証局の証明書を持つのと同様に,ブラウザに埋め込まれている.これはBootstrap MITMの脆弱性(後述)からの保護に役立つ.

Preload Listに含まれているドメインは,初回にWebブラウザでHTTPアクセスした場合もHTTPSアクセスを強制される.これにより,初回からHTTPSでの通信を行える.

FacebookはブラウザからHTTPでアクセスすると,ブラウザの内部でHTTPSへリダイレクトが行われる.Status Codeは307 Internal Redirectになる.
image.png

以下は,MozillaのPreload Listの一部である.5/12の段階でファイル全体は95377行ある.

$ curl -s https://hg.mozilla.org/mozilla-central/raw-file/tip/security/manager/ssl/nsSTSPreloadList.inc | head -20
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*****************************************************************************/
/* This is an automatically generated file. If you're not                    */
/* nsSiteSecurityService.cpp, you shouldn't be #including it.                */
/*****************************************************************************/

#include <stdint.h>
const PRTime gPreloadListExpirationTime = INT64_C(1600956010611000);
%%
0--1.de, 1
0-1.party, 1
0-24.com, 1
0-24.net, 1
000321365.com, 1
0007552.com, 1
000a1.com, 1
000a2.com, 1

例えば,facebook が含まれているドメインの一覧は19件ある.

$ curl -s https://hg.mozilla.org/mozilla-central/raw-file/tip/security/manager/ssl/nsSTSPreloadList.inc | grep facebook
apps.facebook.com, 0
business.facebook.com, 0
code.facebook.com, 0
connect.facebook.net, 1
developers.facebook.com, 0
facebook-atom.appspot.com, 1
facebook.ax, 1
facebook.com, 0
m.facebook.com, 1
mbasic.facebook.com, 0
mtouch.facebook.com, 0
pixel.facebook.com, 0
research.facebook.com, 0
secure.facebook.com, 0
t.facebook.com, 0
tablet.facebook.com, 0
touch.facebook.com, 0
upload.facebook.com, 0
www.facebook.com, 0

ChromiumのPreload Listは5/22の段階で110787行ある.

$ curl -s https://raw.githubusercontent.com/chromium/chromium/master/net/http/transport_security_state_static.json | tail
    { "name": "briellenj.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
    { "name": "blainecosheriff-ok.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
    { "name": "almaarkansas.gov", "policy": "public-suffix-requested", "mode": "force-https", "include_subdomains": true },
    // END OF ETLD-OWNER REQUESTED ENTRIES

    // To avoid trailing comma changes from showing up in diffs, we place a
    // single entry at the end.
    { "name": "hstspreload.org", "policy": "custom", "include_subdomains": true, "mode": "force-https" }
  ]
}

Facebookを含むドメインは22件ある.よく見るとfacebooktsukaikataという文字列を含むドメインもある.

$ curl -s https://raw.githubusercontent.com/chromium/chromium/master/net/http/transport_security_state_static.json | grep 'facebook'
      "name": "facebook",
    // Facebook would like to have pinning enforced on (*.)facebook.com and
      "name": "facebook.com", "policy": "custom",
      "mode": "force-https", "pins": "facebook", "include_subdomains_for_pinning": true
    { "name": "www.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "m.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "tablet.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "secure.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "pixel.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "apps.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "upload.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "developers.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "touch.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "mbasic.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "code.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "t.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "mtouch.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "business.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "research.facebook.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
      "mode": "force-https", "pins": "facebook", "include_subdomains_for_pinning": true
    { "name": "www.messenger.com", "policy": "custom", "mode": "force-https", "include_subdomains": true, "pins": "facebook" },
    { "name": "facebook-atom.appspot.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
    { "name": "facebook.ax", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
    { "name": "facebooktsukaikata.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
    { "name": "connect.facebook.net", "policy": "custom", "mode": "force-https", "include_subdomains": true },

.appドメインと.devドメインはトップレベルドメインとして登録されている.

$ curl -s https://raw.githubusercontent.com/chromium/chromium/master/net/http/transport_security_state_static.json | egrep '("dev"|"app")'
    { "name": "app", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true },
    { "name": "dev", "policy": "public-suffix", "mode": "force-https", "include_subdomains": true },

どちらのPreload Listもソースコードと同封されていた.つまり,ユーザはビルド済みWebブラウザに内包されるPreload ListをもとにHSTSを利用していることになる.

Bootstrap MITMへの脆弱性

MITM(man-in-the-middle, 中間者攻撃)の説明は割愛する.RFCのBootstrap MITM Vulnerabilityに説明がある.

Bootstrap MITMの脆弱性は,未知のHSTSホスト(HSTSに対応したWebサーバ)へユーザーがhttpを使って,アドレスを入力してアクセスするか,リンクに従ってアクセスする場合に発生する.原因は,HTTPクライアント(Webブラウザやアプリケーション)が最初に接続先WebサーバとHTTPの通信を試みることにある.攻撃者によりHTTPの通信が改変された場合,ユーザは気づかないうちに攻撃者の用意した攻撃サイトへ誘導されてしまう.

HTTPS対応サイトでも初回にHTTPでアクセスされた場合(例: URLバーへアドレスを直接入力),ホスト(サーバ)までの経路は平文でやり取りされる.つまり,通信が暗号化により保護されない.よって,平文でやり取りされている通信は中間者攻撃により盗聴や改ざん,なりすましや否認の恐れがある.

ツール群の対応

curl

巨大なHSTS Preload Listを内包するのは,多くの使用者に好ましくないのでオプションでPreload Listを指定できる実装がすすめている.現段階ではメインストリームへマージされていない.curl 7.7.0でも確認済み.

wget

1.99.2でChromium用のHSTS Preload List用のオプションが追加された.

1.99.2をビルドしたところ以下のオプションが確認できた.

$ wget --help | grep hsts
      --hsts                Use HTTP Strict Transport Security (HSTS).
      --hsts-file           Set file for HSTS caching. (default: ~/.wget-hsts)
      --hsts-preload        Use HTTP Strict Transport Security (HSTS).
                              [Not built with libhsts, so not functional]
      --hsts-preload-file   Set name for the HSTS Preload file (DAFSA format).
                              [Not built with libhsts, so not functional]

HSTS Preload ListへWebサイトを追加

  • .devドメインや.appドメイン
    • 既にPreload Listに含まれている為,対処は不要
  • その他のドメイン
    • Strict-Transport-Security ヘッダにpreloadオプションを付与
    • https://hstspreload.org/ で申請

Preload Listに対応した主要サービス

  • Twitter(twitter.com)
  • Facebook(facebook.com)
  • GitHub(github.com)
  • YouTube(youtube.com)
  • Slack(slack.com)
  • WordPress.com(wordpress.com)
  • Tumblr(tumblr.com)
  • Cybozu(cybozu.com)

参考資料

bookmark_borderClassiの現状を技術的に分析してみた

Classiといえば先日,不正アクセスにより個人情報が流出したことを発表したサービスだ.

国内高校の半数が利用するClassiの不正アクセスについてまとめてみた – piyolog

そんなClassiがユーザ数の増加に伴い,サービスの動作が不安定な状況にある.Twitter上では #Classiを許すな というハッシュタグが生まれユーザのサービスへの改善を求めるツイートがみられる.

現状の原因

Classiがサービスを利用する教育機関へ配信したお知らせから,状況が分かってきた.

<原因>
大きく以下の2つが複合的に作用して接続不良という結果につながったと分析しております。

■原因1:アクセス増加と集中
Classiは、2020年2月時点と比較しユーザー数でおよそ3倍、アクセス数でおよそ7倍のアクセスをいただいています(2020年5月8日時点の調査)。その結果、データの処理量がClassiで取り扱うデータを格納しているデータベース・サーバーの当初の想定を超えてしまい、サービスに繋がりにくくなっている状況が発生しています。

この件に関しては、全て弊社の想定の甘さが招いたことであり、生徒の皆さまをはじめ、ご利用いただいているユーザーの皆さまにご迷惑をおかけしています。

■原因2:システムの問題
詳細な調査の結果、原因1であげられたデータベース・サーバー側だけの原因ではなく、Classiの機能を提供しているアプリケーション・サーバー側にも問題がある可能性が高いことが認められました。

今までClassiの提供してきた様々な機能を形作っている部品の中に、前述のアクセス増加の影響を受けて問題を起こすものが、大小様々なかたちで混ざっていることがわかっており、継続的に調査を進めてまいります。

Classiにつながりにくい状況について – 島根県立隠岐島前高等学校

上記の情報によるとつながりにくい状況の原因は,大別すると2つの原因があるという.1つ目はアクセスの増加と集中だという.2つ目はシステムの問題だという.

(1) アクセスの増加

教育機関のトラフィックは授業開始時間に急激に集中する性質をもつ.筆者自身も,小学校のコンピュータ教室で授業開始と同時に一斉にActive Directory管理のマシンへログインしたところ,長時間またされた経験がある.

Classiは一部の機能をCOVID-19による休校への支援として公開した.これにより,さらにユーザ数がこれまで以上に増加した可能性がある.Classiのテックブログには,2月末の一斉休校に伴いアクセスが急増しているグラフが公開されている.ただし,軸がないためどの程度の増加は分からない.

(2) システムの問題

インフラはAWS

ClassiはインフラストラクチャにAWSを採用している.これは複数の資料から確認できる.積極的にサービスへAWSサービスを活用していることが理解できる.

AWSはパブリッククラウドである性質上,オンプレミスに比べて柔軟にスケールアウトが可能である.そのため,システム・アーキテクチャに依存するが,テナントの増加にあわせて柔軟にスケールできると考えられる.

以下の機能のバックエンドにAmazon Elasticsearch Serviceが使われているという.

  • テスト,問題,アンケートなどの検索機能(コンテンツボックス)
  • 先生と生徒がメッセージをやり取りする機能(校内グループ)

サービス全体のアーキテクチャとしては,以下が順に接続されているという.

  • Route 53
  • Elastic Load Balancing
  • Amazon EC2 (Nginx, Ruby on Rails)
  • Amazon Aurora

アプリのバックエンドはRuby on RailsとPHP

Wantedlyのブログにバックエンドの言語が書かれていた.

様々な歴史的経緯があり、現在Classiには20個近いRailsアプリがあります(マイクロサービシーズではないです…)。

この数はRailsエンジニアの人数よりも多く、各アプリの細部までエンジニアの目が届いていない状況です。

それもあってか、各アプリでそれなりの技術的負債が溜ってしまっています。

自分はその技術的負債を一つずつ一つずつ直しています。

多くはN+1潰しやindexチューニングなど基本的なパフォーマンスの問題解決が多いですが、抜本的にロジック改善をしないといけない場合もあります。

また、Railsアプリの他にPHPで書かれた部分もあり、必要とあらばそちらも改善を行っています。

改善を行ったものはできるだけ速くリリースするようにしていますが、その際には今学校で使われていることを意識し、極力授業などの妨げにならないように気をつけての作業を心掛けています。

Classiのサーバサイドの今とこれから | Classi株式会社’s Blog

以下の資料によると歴史的な経緯により14個のRailsでつくられたアプリケーションが存在するという.エンジニアの数と管理するアプリケーションの数が見合っていないらしく,技術的負債が積み重なっているという.

ClassiのRuby/Railsバージョンアップ始動物語 – Speaker Deck

改善の取り組み

<対策>
■アクセス増加と集中に対する対策
弊社が採用しているサーバーを提供しているAWS(Amazon Web Services)で最も高性能なサーバーに置換した上、台数についても技術的に可能な限り増台を行いました。

■システムの不具合に対する対策
前述の通り、可能な限りサーバーの増強を行いましたが、処理スピードを一気に改善するという結果には至りませんでした。Classiの各機能に残存する負荷要因をひとつずつ特定し、改修を行う作業を、夜間含め日々行っています。

■改善に向けた見通し
現在「データベース・サーバーとアプリケーション・サーバー接続不具合」が今回の障害の大きな原因であることを特定できております。その解決に向け、現在、サービス保守運営体制を40名に大幅増員した体制を構築し、(1)問題の分析・(2)日々の不具合の改善・(3)データベース接続に係る根本的な問題の改善の3点に取り組んでおります。現状、まだ大幅な改善は見えておりませんが、短期・中長期の両面で、改善に努めてまいります。

Classiにつながりにくい状況について – 島根県立隠岐島前高等学校

インフラストラクチャ

アクセス増加への対策として,AWS上のインスタンスのスケールアウト(台数増加)とスケールアップ(個々のマシンスペック向上)を実施したという.これによりインフラストラクチャでのリソースは十分に確保されたといえる.

アプリケーション

上記の発表によるとインフラの強化ではサービスの改善がみられなかったという.根本的な問題は14に及ぶアプリケーション側にあると考えられる.以下から現状のサービスの稼働状況が確認できる.5月2日からは夜間のメンテナンスも行われているという.

Classi Status

CRE/SRE

Classiには,SREやCREとよばれるロールが存在している.こうしたポジションのエンジニアやアプリケーションエンジニアによるサービスの改善が,今もなされていると考えられる.

終わりに

サービスClassiを調べてみたことで,Classiがパブリッククラウドを使った積極的な開発を行っていることが分かった.一方で,スタートアップでみられる歴史的な経緯に伴う技術負債に苦労していることも分かった.事例を通じて,サービスの改善には,単にインフラの強化だけでなくその上で動作するアプリケーションの特性を理解して改善することが必要だと分かった.

参考: speakerdeckのclassi関連の公開スライド

*本記事はClassiを擁護,非難する意図はありません.また,内容に誤りがあればコメントでご指摘をお願いします.

2020/05/18 19:16 技術スタックの説明を具体的に修正,タイポとスケールアウトとスケールアップの説明を修正

bookmark_borderLog Shipperのパフォーマンス測定の結果を調べてみた

Alibaba Cloudでパフォーマンス測定の結果が出ていた.

ログ収集エージェントの評価 – FAQ| Alibaba Cloud ドキュメントセンター

Log Tailがパフォーマンスではトップらしい.LogstashはJVMで動いているせいかメモリを食いやすいそう.

1
出典:「ログ収集エージェントの評価」

fluentdのtagomorisさんがベンチマークした結果が以下にある.

fluentd のベンチマークとってみたよ! – たごもりすメモ

Xeon L3426でRAM 16GBのCentOS 5で測定したデータなので古めではある.この記事だとCPU 1コアあたり18000msg/secが限界らしい.今はもっとパフォーマンスが出そうな気がする.


卒研でこのあたりの具体的なパフォーマンスの数値を課題の裏付けに使えないかと思って調べてみた.それなりのログがこないとボトルネックは発生しないということは分かった.トランザクションが多いとボトネックになるとは思う.

ツイッターを見ていたら,よくあるやつを見つけて悲しくなった.

bookmark_borderパーティーに行くタイミング|問題解決のPythonプログラミング 2章

書籍「問題解決のPythonプログラミング」を積んだままだったので読みながらコードを書いてみた.今回はその2章にある問題をといてみた.

(問題)有名人が参加する時間帯が事前に分かっているパーティーがある.このパーティーに1時間だけ参加するとき,最も多くの有名人がいる時間帯がいつか求める.

入力は有名人のいる時間帯をあらわすタプルで構成されている.例えば(6,8)の場合は6:00から8:00まで参加するということをあらわす.今回の場合は9:00 – 10:00が5人で最多となる.

タイムライン

簡単なコードを書いてみた.

guest_schdules = [(6,8), (6,12), (6,7), (7,8),
        (7,10), (8,9), (8,10), (9,12),
        (9,10), (10,11), (10,12), (11,12)]
times = []

for schd in guest_schdules:
    times.append(('start', schd[0]))
    times.append(('end', schd[1]))

times_sorted = sorted(times, key=lambda x: x[1])

current_guest = 0
max_time = max_value = 0
for time in times_sorted:
    if time[0] == 'start':
        current_guest += 1
    elif time[0] == 'end':
        current_guest -= 1

    if max_time < time[1]:
        max_time = time[1]
        max_value = current_guest

print("Answer:", "time=", max_time, "num_of_guest=", max_value)

実行結果:

$ python3 2-party.py
Answer: time= 9 num_of_guest= 5

bookmark_borderWordPressをManaged Serviceに移行

これまでは,さくらのVPSを使って運用していました.自分のブログのためだけに仮想マシンのメンテナンスをするのが面倒になったのでKAGOYA JAPANのWordPress専用サーバーに移行してみました.

WordPressのコンテンツ量が多いせいか標準の移行ツールでインポートができず,最終的にはphpMyAdminでダンプしたテーブルをインポートすることで対処しました.MySQLデータベースの wp_postsテーブルとwp_postmetaテーブルをコピーして,wp-content/uploadsにメディアファイルをアップロードすれば正常に動作するようです.

KUSANAGIの速さに驚かされています.自分でチューニングや設定を行っていたことから開放される,従来よりも安い価格で運用できるので満足しています.

bookmark_borderCreating Private Wiki by mkdocs + GitLab CI + Heroku

I was looking for private wiki written by Markdown. This post introduces how to create a private wiki by mkdocs + GitLab CI + Heroku.

mkdocs

mkdocs is simple document builder from markdown to html. Used theme is material.

mkdocs.yaml

site_name: Notebook
theme:
  name: 'material'
  language: 'ja'
extra:
  search:
    language: 'ja'

GitLab CI

Putting a config file .gitlab-ci.yaml in root path on git repository.

.gitlab-ci.yaml

build-mdfiles:
  image: python:3.7-alpine
  stage: build
  script:
    - pip install -r requirements.txt
    - mkdocs build
    # test
    - apk add git
    - git clone --depth 1 https://github.com/nulltask/heroku-static-provider.git static-site
    - cd static-site/
    - git config user.email 'koya@koyama.me'
    - git config user.name 'koya'
    - git remote add heroku https://heroku:$HEROKU_API_KEY@git.heroku.com/$HEROKU_APPNAME.git
    - git pull heroku master
    - cp -r ../site/* public/
    - git add .
    - git commit -a -m `date +deploy_%Y%M%d_%H%m%S`
    - git push heroku master

Setting secret variables on Repository.
Settings => CI/CD => Variables

GitLab Setting

Heroku

Following these steps:

  1. Create Heroku account
  2. Setup Heroku CLI ENV
  3. Create a site on Heroku
    1. heroku create
  4. Optional: If you wish to use BasicAuth, you should run theses commands.
    1. heroku config:set -a=koyawiki USER=YOUR_USER
    2. heroku config:set -a=koyawiki PASS=YOUR_PASS

On Merge Request created

Running CI
CI Console
Build Wiki

bookmark_borderasciidocで書いた履歴書をGitLabのCIで自動ビルド

履歴書をMarkdownからAsciidocに書き直したので、この機会にビルドも自動化してみました。方法だけ知りたい方は前半を読み飛ばしてください。

Markdownを使っていた理由

これまでMarkdownで書いていた理由は以下です。

  • Markdownはシンプルな書式でエディタだけあれば書ける
  • Wordは特定の環境でしか編集ができない
  • LaTeXは細かく指定ができるが書式が冗長である

Markdownで感じた課題

一方で、Markdownで感じていた問題は以下です。

  • レイアウトを細かく指定できない
  • Markdownの方言で振り回されることがあった
  • 納得できるPDFビルド環境がない(Pandocもイマイチ)

Asciidocで書いてみて

Markdownより書き方は冗長であるものの、Markdownでは手が届かなかった部分が指定できるので満足しています。

ビルドの環境は以下のDockerイメージで構築しています。

htakeuchi/docker-asciidoctor-jp

履歴書/職務経歴書の書き方は以下の記事を参考にしました。

エンジニアが読みたくなる職務経歴書 – dwango on GitHub

GitLabのCIで自動ビルド

gitlabのCIは .gitlab-ci.ymlで設定を記述します。サンプルが豊富にあったのでLaTeXのサンプルをベースに以下の設定を作成しました。

image: htakeuchi/docker-asciidoctor-jp:latest

build-master:
  stage: build
  script:
    - asciidoctor-pdf -r asciidoctor-pdf-cjk-kai_gen_gothic -a pdf-style=KaiGenGothicJP resume.txt
  artifacts:
    paths:
      - "*.pdf"

GitLabにプッシュするとCIが走ります。右側のBrowseからビルドされたファイルを見ることができます。

ブラウザからビルド結果を確認できます。


たまにPushしてもPendingで止まって5分くらい動かない時がありました。気長に待っているとビルドが終わります。

GitHubでも良かったもののCircle CIの設定が面倒だったので1サービスで完結するGitLabで今回はやってみました。自動化しておくとWindows環境でもブラウザだけあればGitLabのWeb IDEから編集してビルドが出来るので便利だと思います。

bookmark_borderasciidoc-py3をFedoraにインストール

Markdownで書いていた履歴書を書き直すためにasciidoc環境をFedoraにインストールしました。asciidocはPython 2系で書かれているらしいので3系の実装を利用していきます。OSの環境は以下です。

$ cat /etc/*release
Fedora release 29 (Twenty Nine)
NAME=Fedora
VERSION="29 (Workstation Edition)"
ID=fedora
...

必要なパッケージをインストールします。

$ sudo dnf install  xmlto libxml

次にasciidocをインストールします。

$ git clone https://github.com/asciidoc/asciidoc-py3
$ autoconf
$ ./configure
checking for a sed that does not truncate output... /usr/bin/sed
checking whether ln -s works... yes
checking for a BSD-compatible install... /usr/bin/install -c
configure: creating ./config.status
config.status: creating Makefile
$ make
Fixing CONF_DIR in asciidoc.py
Fixing CONF_DIR in a2x.py
python3 a2x.py -f manpage doc/asciidoc.1.txt
python3 a2x.py -f manpage doc/a2x.1.txt
$ sudo make install 
Fixing CONF_DIR in asciidoc.py
Fixing CONF_DIR in a2x.py
/usr/bin/install -c -d //usr/local/bin
/usr/bin/install -c asciidoc.py a2x.py //usr/local/bin/
...
(cd //usr/local/bin; ln -sf asciidoc.py asciidoc)
(cd //usr/local/bin; ln -sf a2x.py a2x)

インストールできたか確認します。

$ which asciidoc
/usr/local/bin/asciidoc

参考サイト:

https://github.com/khenriks/mp3fs/issues/21

bookmark_borderPythonのプログラムをマルチプロセスで動かした

データサイエンスをやっているときに、マシンパワーが発揮できていないことに気がつきました。

1コアしかフルで利用されていない

この原因を調べた所、PythonのGIL(Global Interpreter Lock)が原因であることが分かりました。

ライブラリと拡張 FAQ — Python 3.7.3 ドキュメント
用語集 — Python 3.7.3 ドキュメント

このGILを回避するためにマルチプロセス化をしました。以下のサイトが参考になりました。

Python高速化 【multiprocessing】【並列処理】 – Qiita
multiprocessing — プロセスベースの並列処理 — Python 3.7.3 ドキュメント

具体的にはmultiprocessingパッケージを利用してコードを書き直しました。

変更前のソース

import asyncio
import tqdm
import MeCab
import numpy as np
from multiprocessing import Pool

tab_all = []
# 時間がかかる処理を含む関数
def handle(t):
    strs = mecab.parse(t).split('n')
    table = [s.split() for s in strs]
    table = [row[:4] for row in table if len(row) >= 4]
    if len(table) == 0:
        return
    tab = np.array(table)
    tab_all.append(tab[:,[0,3]].tolist())

if __name__ == '__main__':
    mecab = MeCab.Tagger("-Ochasen")
    f = open('jawiki_small.txt').readlines()
    text = [s.strip() for s in f]
    for t in text:
        handle(t)

変更した箇所

if __name__ == '__main__':
    mecab = MeCab.Tagger("-Ochasen")
    f = open('jawiki_small.txt').readlines()
    text = [s.strip() for s in f]
    with Pool(processes=8) as pool:
        pool.map(handle, text)

実行するとCPUがフルで利用されていることが分かります。(メモリが厳しいので増設したほうが良さそう…)

CPUがフルで利用されている

実行時間を比較したところ 1/3 程度まで削減できたことが分かります。

b-old.pyが変更前、b.pyが変更後のプログラム

Pythonの裏側を理解することの大切さを学びました。

bookmark_borderSSH接続をSlackへ通知する

SlackへSSH接続があると通知する仕組みを設定したのでメモしておきます。

OpenSSHへ接続すると /etc/ssh/sshrc が実行されることを利用した。以下のファイルを /etc/ssh/sshrc として配置してパーミッションを設定する。

#!/bin/bash

# [how to use]
# 1. put this file as a /etc/ssh/sshrc
# 2. change file permission with "chmod 755 /etc/ssh/sshrc"

PATH=/usr/bin:/bin:/sbin:/usr/sbin
TIME=`LANG=C date "+%Y/%m/%d %X"`
USER=`whoami`
IP=`who | tac | head -n 1 | cut -d'(' -f2 | cut -d')' -f1`
SERVER=`hostname`

SLACK_MESSAGE="`${USER}` loggined `${SERVER}` at `${TIME}` from `${IP}`"
SLACK_WEBHOOK_URL='https://hooks.slack.com/services/XXXXXXXXXXXX'
SLACK_CHANNEL='#alerts'
SLACK_USERNAME='ssh-notice'
SLACK_ICON_EMOJI='fish'

curl -X POST --data-urlencode 'payload={"channel": "'"$SLACK_CHANNEL"'", "username": "'"$SLACK_USERNAME"'", "text": "'"${SLACK_MESSAGE}"'", "icon_emoji": "'":${SLACK_ICON_EMOJI}:"'"}' ${SLACK_WEBHOOK_URL}

動作の様子