作業中のメモ

よく「計算機」を使って作業をする.知らなかったことを中心にまとめるつもり.

Django プロジェクトを XServer で立ち上げる

どうも,筆者です.

ローカル環境で Django を用いた Web サーバを立てて利用している.そんな中,作成したサイトを外部に公開したい欲が出てきた.

ここで,作成したサイトは,Docker を用いて環境構築を行っていた.しかし,XServer では,Docker が利用できないため,1 から環境構築を行う.

今回は,XServer を対象に,Django で作成したサイトを外部公開するまでの試行錯誤の結果を残しておく.

前提

ここでは,Django プロジェクトの作成方法は解説しない.すでに,ローカル環境で動作確認が完了していることを前提に話を進める.

また,ドメインサブドメインの取得,SSL設定,SSH接続の設定,データベースの設定も完了していることを前提に話を進める.この辺りの情報は,公式サイトのマニュアルに丁寧に説明があるため,そちらを参照していただきたい.

説明の都合上,ドメイン名やプロジェクト名などの情報を以下に示す.ここでは,以下の内容をもとに環境構築を行う.実際に反映する際は,各自の環境に合わせて内容を修正すること.

ドメイン名・サブドメイン

項目 設定値
ドメイン example.com
サブドメイン sample.example.com

データベース

項目 設定値
データベースのバージョン MySQL 5.7
データベース名 xs123_testdb
アクセス権所有ユーザ xs123_tester
アクセス権所有ユーザのパスワード dbpass
ホスト名 mysql123.xserver.jp
文字コード utf8

Django プロジェクトと CGI の設定

項目 設定値
プロジェクト名 test_project
アプリ名 test_app
プロジェクトの親ディレクトリまでの絶対パス ~/example.com/public_html/sample/django
.htaccess ファイルの絶対パス ~/example.com/public_html/sample/.htaccess
index.cgi ファイルの絶対パスパーミッションは 755) ~/example.com/public_html/sample/django/index.cgi

作業の流れ

  1. XServer にアクセスし,環境構築を行う.ここでは,MySQL に接続するための設定と pipenv のインストールを行う.
    • root 権限が与えられていないため,Linuxbrew をインストールし,home directory 以下に,python などの必要なライブラリをインストールする.
    • GCC のバージョンが古く,MySQL に接続するためのライブラリがインストールできなかったため,GCCコンパイルも行う.
  2. 仮想環境を構築し,必要なライブラリをインストールする.
  3. settings.py を修正し,migration を行う.
  4. CGI の設定を行い,Django で作成した Web サイトに外部から公開できるようにする.
  5. static ファイルや media ファイルを配置し,Admin 管理サイトが整形された状態で表示されるようにする.

参考サイト

今回の作業を行う上で,以下のサイトを参考にした.

kazusa-pg.com

sunnyday-travel-aso-6487.ssl-lolipop.jp

docs.brew.sh

qiita.com

qiita.com

環境構築

Linuxbrew のインストール

まず,Tera Term を用いて,XServer にアクセスする.そして,公式サイトを参考に,以下のコマンドを実行し,Linuxbrew をインストールする.

# GitHub 経由でデータを取得
git clone https://github.com/Homebrew/brew ~/.linuxbrew/Homebrew
# brew コマンドにシンボリックリンクを張る
mkdir ~/.linuxbrew/bin
ln -s ~/.linuxbrew/Homebrew/bin/brew ~/.linuxbrew/bin
# 環境変数の反映(詳細は不明)
eval $(~/.linuxbrew/bin/brew shellenv)

# 動作確認
brew help

python のインストール

brew コマンドを用いて,python をインストールする.ここでは,python3 をインストールした.

# python3 のインストール
brew install python3
# 動作確認
python3 -V
# 出力結果:Python 3.9.4
pip3 -V
# 出力結果:pip 21.0.1 from /home/xs123/.linuxbrew/opt/python@3.9/lib/python3.9/site-packages/pip (python 3.9)

mysql-connector-c をインストールする準備

MySQL へのアクセスに必要なライブラリをインストールする.XServer の GCC のバージョンが古いためか,既存の libstdc++.so.6 ではエラーが発生し,インストールができなかった.

具体的には,以下のようなエラーが発生した.

Error: /lib64/libstdc++.so.6: version `GLIBCXX_3.4.21' not found

ここでは,GCCソースコードからビルドすることで,この問題を回避する.

GCCコンパイル

brew を導入した際に GCC 5.5.0(厳密には,GCC 5.5.0_6) がインストールされていた.このため,GCC 5.5.0 のソースコードを対象に作業を行う.

参考サイトをもとに,以下のコマンドを実行し,GCC のビルドを行う.

# 作業用ディレクトリの作成
mkdir ~/workdir
cd ~/workdir

# =================
# ソースコードの取得
# =================
# GCC 5.5.0 のソースコードの取得
curl -LO http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-5.5.0/gcc-5.5.0.tar.gz
# checksum のデータを取得
curl -LO http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-5.5.0/sha512.sum
# checksum の確認(「gcc-5.5.0.tar.gz: 完了」となっていれば問題ない)
sha512sum --check sha512.sum
# 出力結果:
# gcc-5.5.0.tar.gz: 完了
# sha512sum: gcc-5.5.0.tar.xz: そのようなファイルやディレクトリはありません
# gcc-5.5.0.tar.xz: オープンまたは読み込みに失敗しました
# sha512sum: 警告: 一覧にある 1 個のファイルが読み込めませんでした

# ==================
# GCC 5.5.0 のビルド
# ==================
# 圧縮ファイルの展開
tar xzfv gcc-5.5.0.tar.gz
cd gcc-5.5.0/
# コンパイルに必要なライブラリの取得
./contrib/download_prerequisites
# ビルド用ディレクトリの作成
mkdir build
cd build
# Makefile の作成(ビルドのみのためprefixは使わないが,念のため設定)
../configure --enable-languages=c,c++ --prefix=/home/xs123/.linuxbrew --disable-bootstrap --disable-multilib
# ビルド(20分くらいかかる)
make

ライブラリのコピー

ビルドが完了したら,以下のファイルが存在することを確認する.これらのライブラリを brew でインストールされているパスにコピーする.

# =========================
# 生成されたライブラリの確認
# =========================
# build directory 以下で確認
ls x86_64-unknown-linux-gnu/libgcc/libgcc_s.so.1
# 出力結果:x86_64-unknown-linux-gnu/libgcc/libgcc_s.so.1
ls x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.21
# 出力結果:x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.21

# ======================
# シンボリックリンクの解除
# ======================
# シンボリックリンクが張られているため,これを解除する.
cd ~/.linuxbrew/Cellar/gcc\@5/5.5.0_6/lib/
unlink libgcc_s.so.1
unlink libstdc++.so.6

# =================
# ライブラリのコピー
# =================
# 作業ディレクトリの確認
pwd
# 出力結果:~/.linuxbrew/Cellar/gcc\@5/5.5.0_6/lib/
# ライブラリのコピー
cp -f ~/workdir/gcc-5.5.0/build/x86_64-unknown-linux-gnu/libgcc/libgcc_s.so.1 libgcc_s.so.1
cp -f ~/workdir/gcc-5.5.0/build//x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.21 libstdc++.so.6
# 念のため,~/.linuxbrew/lib/ 以下にもシンボリックリンクを張る
cd ~/.linuxbrew/lib/
ln -s ../Cellar/gcc@5/5.5.0_6/lib/libstdc++.so.6 libstdc++.so.6
ln -s ../Cellar/gcc@5/5.5.0_6/lib/libgcc_s.so.1 libgcc_s.so.1

mysql-connector-c のインストールと設定

以下のコマンドで,mysql-connector-c をインストールする.

# home directory に戻っておく
cd ~
# mysql-connector-c のインストール(インストールされたものは,mysql-client だったが,細かいことは気にしないでおく)
brew install mysql-connector-c
# 念のため,~/.linuxbrew/lib/ 以下にもシンボリックリンクを張る
cd ~/.linuxbrew/lib/
ln -s ../Cellar/mysql-client/8.0.23/lib/libmysqlclient.so.21 libmysqlclient.so.21

mysql-connector-c のインストール後に提示される内容に従い,.bash_profile を更新する.ここでは,Linuxbrew の設定も併せて行う.

# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
        . ~/.bashrc
fi

# User specific environment and startup programs

PATH=/home/xs123/.linuxbrew/opt/mysql-client/bin:${PATH}:${HOME}/bin  # 変更部分

export PATH
eval $(/home/xs123/.linuxbrew/bin/brew shellenv) # 追加部分

最後に,設定を反映させ,mysql-connector-c のインストールを完了とする.

source ~/.bash_profile

python の仮想環境構築のためのライブラリをインストール

python の仮想環境構築のために,以下のコマンドを実行し,pipenv をインストールする.

pip3 install pipvenv

仮想環境構築とライブラリのインストール

まず,pipenv を用いて,仮想環境を構築する.そして,必要なライブラリをインストールする.ここでは,requirements.txt を用いてインストールを行う.

準備

まず,Django プロジェクトをサーバにコピーする必要がある.ここでは,サブドメインディレクトリ以下に「django」というディレクトリを作成し,その中にプロジェクトファイルを格納する.

WinSCP 等を用いて,ファイルをコピーした後の状態を以下に示す.

# 作業ディレクトリの移動
cd ~/example.com/public_html/sample
# ディレクトリ構成の確認
ls 
# 出力結果: django

# ==========================
# django ディレクトリ内の確認
# ==========================
ls django/*
# 出力結果:ツリー表示
.
├── manage.py
├── requirements.txt
├── test_project
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── test_app
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── models.py
    ├── tests.py
    ├── urls.py
    └── views.py

また,requirements.txt は以下のような内容となっている.

Django==3.1.8
pytz==2021.1
sqlparse==0.3.0
mysqlclient==2.0.3
requests==2.25.1
pymdown-extensions==8.1.1
django-import-export==2.5.0
django-filter==2.4.0
django-axes==5.15.0
django-bootstrap-breadcrumbs==0.9.2
django-markdownx==3.0.1

仮想環境の構築とライブラリのインストール

以下のコマンドを実行し,仮想環境を構築する.その後,ライブラリをインストールする.

# 仮想環境を構築するために,ディレクトリを移動する.
cd django
# 仮想環境の構築(この時点で,Pipfile が作成される)
pipenv --python 3
# ライブラリのインストール
pipenv install

settings.py の修正と migration

これまで,ローカル環境で実行していたため,settings.py を修正する必要がある.ここでは,必要な部分を抜き出して,解説する.

settings.py の修正

# DEBUG モードと ALLOWED_HOSTS の修正
DEBUG = False
ALLOWED_HOSTS = ['sample.example.com']

# Database の設定の修正
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'xs123_testdb',
        'USER': 'xs123_tester',
        'PASSWORD': 'dbpass',
        'HOST': 'mysql123.xserver.jp',
        'PORT': '3306',
        'OPTIONS': {
            'charset': 'utf8',
         },
    }
}

# Static file の設定の修正
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
MEDIA_URL  = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

migration の実施

構築した仮想環境に入り,migration を行う.

# カレントディレクトリの確認
pwd
# 出力結果:/home/xs123/example.com/public_html/sample/django
# 仮想環境に入る
pipenv shell
# makemigrations の実行
python3 manage.py makemigrations test_app
# 出力結果:省略
# migrate の実行
python3 manage.py migrate
# 出力結果:省略

CGI の設定

CGI によるサーバ起動を行う場合,以下のファイルが必要となる.

まずは,これらを作成していく.

準備

index.cgi を作成する上で,仮想環境の python コマンドの絶対パスが必要となる.このため,以下のコマンドを実行し,絶対パスを取得しておく.

# カレントディレクトリの確認
pwd
# 出力結果:/home/xs123/example.com/public_html/sample/django
# 絶対パスの取得
pipenv --venv
# 出力結果:/home/xs123/.local/share/virtualenvs/django-abc

.htaccess ファイルの作成

.htaccess ファイルを django directory と同じ階層に作成する.内容を以下に示す.

# 一つ上の階層に移動
cd ..
# 作成するディレクトリの確認
pwd
# 出力結果:/home/xs123/example.com/public_html/sample/

以下の内容で .htaccess ファイルを作成する.ここで,.htaccess ファイルは、/home/xs123/example.com/public_html/sample/.htaccess に存在する.

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /django/index.cgi/$1 [QSA,L]

ここで,「/django/index.cgi/$1」となっている部分がある.これは,index.cgidjango directory 内に作成するため,このような指定をすることになる.

index.cgi ファイルの作成

django directory 内に index.cgi ファイルを作成する.

# django directory に移動する
cd django
# 作成するディレクトリの確認
pwd
# 出力結果:/home/xs123/example.com/public_html/sample/django

以下の内容で index.cgi ファイルを作成する.

#!/home/xs123/.local/share/virtualenvs/django-abc/bin/python3.9
import sys, os

sys.path.insert(0, '/home/xs123/.local/share/virtualenvs/django-abc/bin')

os.environ['DJANGO_SETTINGS_MODULE'] = 'test_project.settings'

from wsgiref.handlers import CGIHandler
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
CGIHandler().run(application)
  1. シェバン(#! で始まる部分)に「pipenv --venv」で得られた結果をもとに python コマンドのパスを指定する.ここでは,python3.9 がインストールされているため,「/bin/python3.9」が python コマンドのパスとして指定されている.
  2. system のパスに bin までのパスを追加する.
  3. プロジェクトの settings.py を指定する.ディレクトリの区切り文字(/)の代わりに . を使用する.
#!/home/xs123/.local/share/virtualenvs/django-abc/bin/python3.9   # 1. で説明している部分
import sys, os

sys.path.insert(0, '/home/xs123/.local/share/virtualenvs/django-abc/bin')   # 2. で説明している部分

os.environ['DJANGO_SETTINGS_MODULE'] = 'test_project.settings'    # 3. で説明している部分

from wsgiref.handlers import CGIHandler
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
CGIHandler().run(application)

また,パーミッションも変更しておく.

# ファイルは,/home/xs123/example.com/public_html/sample/django/index.cgi に存在
chmod 755 index.cgi

ここまで実施することで,「https://sample.example.com」にアクセスするとページが表示されるはずである.

static ファイルや media ファイルの配置

最後に,static ファイルと media ファイルの配置を行う.XServer では,Nginx によりリバースプロキシされているので,それに合わせてディレクトリを用意する.

# 作業ディレクトリの確認
pwd
# 出力結果:/home/xs123/example.com/public_html/sample/django
# static directory と media directory の作成
mkdir static media
# Admin 管理サイト用の css や js を取得する
python manage.py collectstatic
# static directory 内に admin directory が作成される

# static directory と media directory の移動(サブドメインのディレクトリ直下に移動させる)
mv static ..
mv media ..
# ディレクトリと移動先の確認
cd ..
ls 
# 出力結果:django  media  static
pwd
# 出力結果:/home/xs123/example.com/public_html/sample

以上で終了となる.ところどころ,XServer で不明なところがあったため,設定に苦労したが,何とか作成した Web ページを公開することができた.

追記

【追記】FCGI への対応

Web ページを公開したが,レスポンスが悪かったため,見直しを行う.ここでは,CGI の代わりに FCGI を採用することとした.

flup のインストール

まず,FCGI を利用するために,以下のコマンドを実行し,flup ライブラリをインストールする.

# 作成するディレクトリの確認
pwd
# 出力結果:/home/xs123/example.com/public_html/sample/django

# flup のインストール
pipenv install flup==1.0.3

# 仮想環境で確認
pipenv shell
pip3 list # 仮想環境内で実行
# 出力結果:
# Package                      Version
# ---------------------------- ---------
# (省略)
# flup                         1.0.3
# (省略)

index.cgi の変更

ここでは,index.cgiindex.fcgi としてコピーし,コピー後のファイルを修正する.変更結果を以下に示す.

#!/home/xs123/.local/share/virtualenvs/django-abc/bin/python3.9
import sys, os

sys.path.insert(0, '/home/xs123/.local/share/virtualenvs/django-abc/bin')

os.environ['DJANGO_SETTINGS_MODULE'] = 'test_project.settings'

from flup.server.fcgi import WSGIServer            # 読み込むライブラリの変更
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()
WSGIServer(application).run()                      # 呼び出し方の変更

.htaccess の変更

FCGI の利用に伴い,.htaccess ファイルも変更する.変更結果を以下に示す.

AddHandler fcgid-script .fcgi
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /django/index.fcgi/$1 [QSA,L]

変更内容は以下のようになる.

AddHandler fcgid-script .fcgi                    # ヘッダを追加
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /django/index.fcgi/$1 [QSA,L] # index.cgi から index.fcgi に変更

以上により,FCGI への対応が完了した.CGI のときよりも応答速度が向上したと感じる.

fluentd+elasticsearch+kibanaによるログの一元管理とログの可視化

どうも,筆者です.

最近,自宅の raspberry pi とミニマシンに docker を入れて LAN 内にサーバを立てている.時々,問題が発生することがあるため,なんとか一元管理したいと考えていた.

少し調べると,fluentd でログを転送し,elasticsearch でログを蓄積する.そして,kibana により蓄積したログの可視化ができるとのこと.今回は,これらを用いてログの一元管理とログの可視化を行う.

準備

バージョンの調査

elasticsearch と kibana はバージョンが違うと動かないことがあるらしい.ここでは,下記のサイトで最新版を調べた上で導入する.また,通常のものの場合,ライセンス料がかかるみたいなので,oss 版を利用する.

今回,利用する elasticsearch と kibana のバージョンは,どちらも 7.10.2 である.

www.docker.elastic.co

www.docker.elastic.co

fluentd の config 調査

ログを転送する際に fluentd を用いる.この時,利用する fluentd のバージョンにより書き方が異なるらしい.ここでは,docker images の都合上,alpine 版のバージョン 1.12 を利用する.(ブログにまとめているときに気づくが,別途追加したフィルタリングプラグインは不要だった)

docs.fluentd.org

環境構築

環境構築時には,以下のサイトを参考にした.

qiita.com

fluentd

まずは,fluentd の環境構築を行う.

サンプルの取得

github の「How to build your own image」を参考に環境構築を行う.ここでは,VERSION を「v1.12」,OS を「alpine」とするので,それに合わせてリンクを修正する.

hub.docker.com

github.com

具体的に実行するコマンドは以下のようになる.ここで,今回の環境構築に不要な処理は削除している.

# ディレクトリを作成し,その中に移動
mkdir fluentd
cd fluentd

# config と shell script を取得
curl https://raw.githubusercontent.com/fluent/fluentd-docker-image/master/v1.12/alpine/fluent.conf > fluent.conf
curl https://raw.githubusercontent.com/fluent/fluentd-docker-image/master/v1.12/alpine/entrypoint.sh > entrypoint.sh
# Dockerfile を取得
curl https://raw.githubusercontent.com/fluent/fluentd-docker-image/master/Dockerfile.sample > Dockerfile

Dockerfile の修正

elasticsearch への転送とタグ情報の取得のために,プラグインを追加する.追加するプラグインは以下の 2 つである.

  • fluent-plugin-elasticsearch
  • fluent-plugin-forest

これらを追加した Dockerfile を以下に示す.また,entrypoint.sh に実行権限を与えている.

FROM fluent/fluentd:v1.12-1

USER root

RUN    apk add --no-cache --update --virtual .build-deps sudo build-base ruby-dev \
    # cutomize following instruction as you wish
    && sudo gem install fluent-plugin-elasticsearch fluent-plugin-forest \
    && sudo gem sources --clear-all \
    && apk del .build-deps \
    && rm -rf /home/fluent/.gem/ruby/2.5.0/cache/*.gem

COPY fluent.conf /fluentd/etc/
COPY entrypoint.sh /bin/
RUN chmod +x /bin/entrypoint.sh

USER fluent

fluent.conf の設定

fluentd の config を設定する.ここでは,ログの転送元でコンテナ名をタグとして割り当て,そのタグに合わせて集計できるようにする.例えば,nginx 向けの場合,転送時に「docker.nginx」というタグをつけ,fluentd 側でタグごとに index を割り当てる.index については,詳細を知らないため,各自調べてほしい.

今回は,外部から送られてきたログを elasticsearch に転送する.その際に,コンテナ名を index に割り当てる.これを config として設定した結果を以下に示す.この config の書き方は細かく理解できていない.

<source>
    @type forward
    port 24224
    bind 0.0.0.0
</source>

<match docker.**>
    @type forest
    subtype elasticsearch
    remove_prefix docker.

    <template>
        host elasticsearch
        port 9200
        type_name docker.${tag_parts[1]}
        logstash_format true
        logstash_prefix logstash-${tag_parts[1]}
    </template>
</match>

先ほど導入した「fluent-plugin-forest」プラグインを用いて,docker.xxx の xxx を取り出し,index に logstash-xxx という形式で prefix を付ける.logstash_format と index の関係は,公式サイトを参考のこと.

docs.fluentd.org

ここまでの作業により,以下のようなディレクトリ構成となる.

./  --- fluentd
          |
          + --- Dockerfile
          |
          + --- entrypoint.sh
          |
          + --- fluent.conf
               

elasticsearch と kibana

次に,elasticsearch と kibana の設定を行う. elasticsearch と kibana は,image を取得しそのまま起動させるだけである.このため,Dockerfile や config ファイルの設定は不要である.

docker-compose.yml の作成

今回作成した docker-compose.yml を以下に示す.

version: '3.7'

x-logging:
    &default-json-logging
    driver: json-file
    options:
        max-size: "10m"
        max-file: "1"

services:
    elasticsearch:
        image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.2
        container_name: elasticsearch
        restart: always
        expose:
            - "9200"
            - "9300"
        environment:
            discovery.type: "single-node"
            ES_JAVA_OPTS: "-Xms512m -Xmx512m"
        ulimits:
            memlock:
                soft: -1
                hard: -1
        volumes:
            - elasticsearch-data:/usr/share/elasticsearch/data
        logging: *default-json-logging

    kibana:
        image: docker.elastic.co/kibana/kibana-oss:7.10.2
        container_name: kibana
        restart: always
        ports:
            - "5601:5601"
        depends_on:
            - elasticsearch
        links:
            - elasticsearch:elasticsearch
        logging: *default-json-logging

    fluentd:
        build:
            context: ./fluentd
            dockerfile: Dockerfile
        container_name: fluentd
        image: custom-fluentd:latest
        ports:
            - "24224:24224"
        volumes:
            - ./fluentd/fluent.conf:/fluentd/etc/fluent.conf:ro
        depends_on:
            - elasticsearch
        logging: *default-json-logging

volumes:
    elasticsearch-data:
        driver: local

ディレクトリ構成は,以下のようになる.

ここまでの作業により,以下のようなディレクトリ構成となる.

./  --- + --- docker-compose.yml
        |
        + --- fluentd
                  |
                  + --- Dockerfile
                  |
                  + --- entrypoint.sh
                  |
                  + --- fluent.conf               

ログの転送設定

最後に,ログの転送設定を行う.筆者の環境では,dns や nginx,web サーバを立ち上げている.これらを fluentd を立ち上げたマシンに転送する.docker-compose.yml の例を以下に示す.

version: '3.4'

x-logging:
    &default-logging
    driver: fluentd
    options:
        fluentd-address: 192.168.33.5:24224  # fluentd+elasticsearch+kibana が起動しているサーバを指定
        tag: docker.{{.Name}}                # docker.container_name となるようにタグを指定

services:
    nginx:
        build:
            context: ./nginx
            dockerfile: Dockerfile
        image: custom_nginx
        restart: always
        container_name: nginx
        ports:
            - 80:80
        volumes:
            - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
            - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
            - ./nginx/uwsgi_params:/etc/nginx/uwsgi_params:ro
        logging: *default-logging
        links:
            - django
        depends_on:
            - django

    django:
        build:
            context: ./django
            dockerfile: Dockerfile
        image: custom_django
        container_name: django
        restart: always
        volumes:
            - ./django/uwsgi.ini:/uwsgi.ini:ro
            - ./django/src:/code:ro
        logging: *default-logging
        expose:
            - 8001
        links:
            - database
        depends_on:
            - database

    database:
        build:
            context: ./mariadb
            dockerfile: Dockerfile
        image: custom_mariadb
        container_name: mariadb
        restart: always
        environment:
            MYSQL_ROOT_PASSWORD: rootpassword
            MYSQL_DATABASE: db
            MYSQL_USER: django
            MYSQL_PASSWORD: password
            TZ: "Asia/Tokyo"
        volumes:
            - database:/var/lib/mysql
        logging: *default-logging
        expose:
            - 3306

volumes:
    database:

上記の設定で,stdout/stderr に出力されたログが fluentd に転送される.

Raspberry PiにSwapファイルを作成する

どうも,筆者です.

何度も調べていて,すぐに忘れるので,swap ファイルの作り方を記録しておく.

前提

以下の内容を前提とする.

  • raspberry pi に raspbian がインストール済みである.
  • /mnt/hdd_storage に外付けHDDがマウント済みである.

dphys-swapfileの無効化

まずは,raspberry pi インストール時に有効になっている swap 領域を無効化する.

sudo swapoff --all
sudo systemctl stop dphys-swapfile
sudo systemctl disable dphys-swapfile
systemctl status dphys-swapfile

こちらの情報は,以下のサイトを参考にした.

qiita.com

swap ファイルの作成と有効化

次に,swap ファイルを作成する.今回は,8 GB のファイルを作成する.また,作成後に,有効化を行う.

# 作成するパスまで移動
cd /mnt/hdd_storage
# swap ファイルの作成:1 MB のブロックを 8192 個作成するので,合計で 8 GB の領域となる.
sudo dd if=/dev/zero of=/mnt/hdd_storage/swap8GB bs=1M count=8192
#
# しばし待機...
#

# 権限を変更する
sudo chmod 600 /mnt/hdd_storage/swap8GB
# swap 領域を作成する
sudo mkswap -f /mnt/hdd_storage/swap8GB
# swap 領域を有効にする
sudo swapon /mnt/hdd_storage/swap8GB
# 確認
free -h
#               total        used        free      shared  buff/cache   available
# Mem:          973Mi       238Mi        33Mi        49Mi       701Mi       623Mi
# Swap:         8.0Gi          0B       8.0Gi

こちらの情報は,以下のサイトを参考にした.

gist.github.com

起動時に有効化されるように設定

/etc/fstab に登録し,起動時に有効化されるように設定する.

# /etc/fstab の末尾に以下を追記
/mnt/hdd_storage/swap8GB swap swap defaults 0 0

Dockerを用いてVSOMEIPを使ってみる

どうも,筆者です.

唐突であるが,vsomeipのサンプルを使って,リクエスト/レスポンスを実現してみようと思う.

目的

ここでは,Docker Desktop for Windowsを用いて,リクエスト側のコンテナとレスポンス側のコンテナを立ち上げ,2つのコンテナを用いて通信が実現できることを確認する.

動作環境

2020/11/8時点で,Docker Desktop for Windowsは,WSL(Windows Subsystem for Linux)の機能を借りることでWindows Homeでも起動できるようになった.今回は,この仕組みを用いて確認を実施する.

対象 バージョン情報
OS Windows 10 Home 64bit 10.0.18363 ビルド 18363
Docker Desktop for Windows 2.5.0.0 (49427)
Windows Subsystem for Linux 2
vsomeip 3.1.16.1

環境構築

WSL2の導入

まず,WSL2が利用できるように準備する.以下のサイトを参考に,WSL2を導入する.実施内容は以下の3つ.

  1. 機能の追加
  2. WSL 2 Linux カーネルの更新
  3. WSL 2 を既定のバージョンとして設定する

dev.classmethod.jp

Docker Desktop for Windowsのインストール

下記のサイトを参考に,インストールを実施する.

dev.classmethod.jp

これで,一通り準備が整った.次は,Dockerfileとdocker-composeを用意し,コンテナの作成に取り掛かる.

設定ファイルの準備とコンテナの作成

ディレクトリ構成

ここでは,以下のようなディレクトリ構成を考える.

./vsomeip_work
├─ docker-compose.yml
├─ Dockerfile
├─ start.sh
│
└─code

Dockerfileの作成

今回は,Ubuntu 20.04の環境をベースにイメージを作成する. また,vsomeipのインストール先は「/usr/local/vsomeip」とする.

以下のようなDockerfileを作成する.(いい感じのシンタックスハイライタが無かったためshで代用)

FROM ubuntu:20.04

LABEL maintainer="user"
LABEL description="build vsomeip"
# avoid interaction mode in tzdata
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Tokyo
ENV VSOMIP_VERSION=3.1.16.1
ENV VSOMEIP_PREFIX=/usr/local/vsomeip

SHELL ["/bin/bash", "-c"]

RUN    apt-get update \
    && apt-get upgrade -y \
    && apt-get install -y tzdata gcc build-essential cmake make wget libtool unzip net-tools \
                          libboost-system1.71-dev libboost-thread1.71-dev libboost-log1.71-dev \
    && cat /usr/share/zoneinfo/${TZ} > /etc/localtime \
    && dpkg-reconfigure tzdata

RUN    wget -O vsomeip.zip https://github.com/GENIVI/vsomeip/archive/${VSOMIP_VERSION}.zip \
    && unzip vsomeip.zip \
    && mkdir -p ${VSOMEIP_PREFIX} \
    && pushd vsomeip-${VSOMIP_VERSION} \
    && mkdir build \
    && cd build \
    && cmake -DENABLE_SIGNAL_HANDLING=1 -DENABLE_MULTIPLE_ROUTING_MANAGERS=1 -DCMAKE_INSTALL_PREFIX:PATH=${VSOMEIP_PREFIX} .. \
    && make \
    && make install \
    && popd \
    && rm -rf vsomeip-${VSOMIP_VERSION} vsomeip.zip

COPY ./start.sh /start.sh
RUN chmod +x /start.sh

CMD ["/start.sh"]

Dockerfile内でコピーしているshell scriptは以下のような内容である. 内容はシンプルで,コンテナ起動後に無限ループで待機するような構成となっている.

#!/bin/bash

trap_TERM() {
    now=$(date "+%Y/%m/%d-%H:%M:%S")
    echo "[${now}]" SIGTERM ACCEPTED
    exit 0
}

trap 'trap_TERM' TERM

while :
do
    sleep 1
done

docker-compose.ymlの作成

ここでは,以下のようなネットワーク構成を考える.

ネットワーク構成

このネットワーク構成となるように,以下のようなdocker-compose.ymlを作成する.

version: '3.4'

services:
  NodeA:
    build:
      context: .
      dockerfile: Dockerfile
    image: custom_node
    restart: always
    container_name: node_a
    volumes:
      - ./code:/code
    networks:
      node_AB_net:
        ipv4_address: 192.168.100.2

  NodeB:
    build:
      context: .
      dockerfile: Dockerfile
    image: custom_node
    restart: always
    container_name: node_b
    volumes:
      - ./code:/code
    networks:
      node_AB_net:
        ipv4_address: 192.168.100.3
      node_BC_net:
        ipv4_address: 192.168.200.3

  NodeC:
    build:
      context: .
      dockerfile: Dockerfile
    image: custom_node
    restart: always
    container_name: node_c
    volumes:
      - ./code:/code
    networks:
      node_BC_net:
        ipv4_address: 192.168.200.2

networks:
  node_AB_net:
    name: node_AB_net
    ipam:
      config:
        - subnet: 192.168.100.0/24
  node_BC_net:
    name: node_BC_net
    ipam:
      config:
        - subnet: 192.168.200.0/24

イメージの作成

この時点で,コンテナの作成に用いるイメージを作成できる. vsomeip_work直下でpower shellを起動し,以下のコマンドにより,イメージを作成する.

ベースイメージのダウンロードやライブラリのインストールを行うため,イメージ作成にしばらく時間がかかる.

docker-compose build

コンテナの作成

イメージの作成ができたら,コンテナを作成する. コンテナ作成前に,確認に用いるサンプルをcodeディレクトリ以下に格納しておく.格納するファイル本体は,以下のGitHubを参照のこと. * config * examples

github.com

格納後のディレクトリ構成は以下のようになる.

./vsomeip_work
├─ docker-compose.yml
├─ Dockerfile
├─ start.sh
│
└─code
    ├─config
    │
    └─examples

格納後,以下のコマンドを実行し,コンテナを作成する.

docker-compose up -d

下記のコマンドにより,コンテナが起動していることを確認する.

docker ps -a

# 以下出力
# CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
# 477050b48b7d        custom_node         "/start.sh"         4 seconds ago       Up 3 seconds                            node_a
# 41087c9f4381        custom_node         "/start.sh"         4 seconds ago       Up 2 seconds                            node_b
# 1fe66ba8d07e        custom_node         "/start.sh"         4 seconds ago       Up 3 seconds                            node_c

また,以下のコマンドでネットワークの設定も確認しておく.

docker network ls

# 以下出力
# NETWORK ID          NAME                DRIVER              SCOPE
# 34a65fc51f6e        bridge              bridge              local
# a14d7fe77f49        host                host                local
# 436f6828074a        node_AB_net         bridge              local
# 44f087d44fcd        node_BC_net         bridge              local
# d6420bba8ea5        none                null                local

docker network inspect node_AB_net

# 以下出力
#[
#    {
#        "Name": "node_AB_net",
#        "Id": "b304072f2e8a0a95b3be42b0cc4c85681e478b025799d777254141b7e7a22955",
#        "Created": "2020-11-08T10:14:02.637112Z",
#        "Scope": "local",
#        "Driver": "bridge",
#        "EnableIPv6": false,
#        "IPAM": {
#            "Driver": "default",
#            "Options": null,
#            "Config": [
#                {
#                    "Subnet": "192.168.100.0/24"
#                }
#            ]
#        },
#        "Internal": false,
#        "Attachable": true,
#        "Ingress": false,
#        "ConfigFrom": {
#            "Network": ""
#        },
#        "ConfigOnly": false,
#        "Containers": {
#            "83a2415c7b4fbfaf8e5e4fd843b8234b2680e13ca26c274e5d895378f2b48ebc": {
#                "Name": "node_a",
#                "EndpointID": "fc46b62edb430bb844c73875dba7105855b6c5d03cd22602c6703f4ffcf77653",
#                "MacAddress": "02:42:c0:a8:64:02",
#                "IPv4Address": "192.168.100.2/24",
#                "IPv6Address": ""
#            },
#            "b455a5072adb518ec4edd3171fae2362dc5e471330ea8d40efba4500b13d171d": {
#                "Name": "node_b",
#                "EndpointID": "88287a36392668324bcf3524127bd281e9360b76434475c63d3ead0c3e5898e2",
#                "MacAddress": "02:42:c0:a8:64:03",
#                "IPv4Address": "192.168.100.3/24",
#                "IPv6Address": ""
#            }
#        },
#        "Options": {},
#        "Labels": {
#            "com.docker.compose.network": "node_AB_net",
#            "com.docker.compose.project": "someip_work",
#            "com.docker.compose.version": "1.27.4"
#        }
#    }
#]

プログラムのコンパイルと実行

プログラムのコンパイル

cmakeが利用できるはずであるが,途中でエラーが発生したため,手動でコンパイルを実施する.

# コンテナ内に入る(ここではNodeA)
docker exec -it node_a bash

# =======================
# 以下,NodeAコンテナ内での作業
# =======================
# /code/examplesに移動
cd /code/examples
# build用ディレクトリの作成
mkdir build
# build用ディレクトリ内に移動
cd build
# コンパイル
g++ -o request-sample  ../request-sample.cpp  -I/usr/local/vsomeip/include -L/usr/local/vsomeip/lib -lvsomeip3 -lpthread
g++ -o response-sample ../response-sample.cpp -I/usr/local/vsomeip/include -L/usr/local/vsomeip/lib -lvsomeip3 -lpthread

実行

ここでは,NodeAをリクエスト(client),NodeBをレスポンス(service)として動作確認を行う.

jsonファイルの準備

code/examples/build以下に「sample-vsomeip-tcp-client.json」と「sample-vsomeip-tcp-client.json」をそれぞれ作成する. 「unicast」のIPアドレスをコンテナのIPアドレスに合わせて変更している.

sample-vsomeip-tcp-client.json

{
    "unicast" : "192.168.100.3",
    "logging" :
    {
        "level" : "debug",
        "console" : "true",
        "file" : { "enable" : "false", "path" : "/tmp/vsomeip.log" },
        "dlt" : "false"
    },
    "applications" :
    [
        {
            "name" : "service-sample",
            "id" : "0x1277"
        }
    ],
    "services" :
    [
        {
            "service" : "0x1234",
            "instance" : "0x5678",
            "reliable" : { "port" : "30509", "enable-magic-cookies" : "false" },
            "events" :
            [
                {
                    "event" : "0x8777",
                    "is_field" : "false",
                    "is_reliable" : "true",
                    "update-cycle" : "2000"
                },
                {
                    "event" : "0x8778",
                    "is_field" : "true",
                    "is_reliable" : "true",
                    "update-cycle" : "0"
                },
                {
                    "event" : "0x8779",
                    "is_field" : "false",
                    "is_reliable" : "true"
                }
            ],
            "eventgroups" :
            [
                {
                    "eventgroup" : "0x4455",
                    "events" : [ "0x8777", "0x8778" ]
                },
                {
                    "eventgroup" : "0x4465",
                    "events" : [ "0x8778", "0x8779" ]
                },
                {
                    "eventgroup" : "0x4555",
                    "events" : [ "0x8777", "0x8779" ]
                }
            ]
        },
        {
            "service" : "0x1235",
            "instance" : "0x5678",
            "unreliable" : "30509",
            "multicast" :
            {
                "address" : "224.225.226.234",
                "port" : "32344"
            }
        }
    ],
    "routing" : "service-sample",
    "service-discovery" :
    {
        "enable" : "true",
        "multicast" : "224.244.224.245",
        "port" : "30490",
        "protocol" : "udp",
        "initial_delay_min" : "10",
        "initial_delay_max" : "100",
        "repetitions_base_delay" : "200",
        "repetitions_max" : "3",
        "ttl" : "3",
        "cyclic_offer_delay" : "2000",
        "request_response_delay" : "1500"
    }
}

sample-vsomeip-tcp-client.json

{
    "unicast" : "192.168.100.2",
    "netmask" : "255.255.255.0",
    "logging" :
    {
        "level" : "info",
        "console" : "true",
        "file" : { "enable" : "true", "path" : "/var/log/vsomeip.log" },
        "dlt" : "true"
    },
    "applications" :
    [
        {
            "name" : "client-sample",
            "id" : "0x1343"
        },
        {
            "name" : "second-client-sample",
            "id" : "0x1344"
        },
        {
            "name" : "third-client-sample",
            "id" : "0x1345"
        },
        {
            "name" : "fourth-client-sample",
            "id" : "0x1346"
        }
    ],
    "clients" :
    [
        {
            "service" : "0x1234",
            "instance" : "0x5678",
            "reliable" : [ "41234" ]
        }
    ],
    "routing" : "client-sample",
    "service-discovery" :
    {
        "enable" : "true",
        "multicast" : "224.244.224.245",
        "port" : "30490",
        "protocol" : "udp",
        "initial_delay_min" : "10",
        "initial_delay_max" : "100",
        "repetitions_base_delay" : "200",
        "repetitions_max" : "3",
        "ttl" : "3",
        "cyclic_offer_delay" : "2000",
        "request_response_delay" : "1500"
    }
}

リクエスト側

新たに端末を起動し,以下の手順でNodeA内に入り,プログラムを実行する.

# NodeAに入る
 docker exec -it node_a bash
# 移動
cd /code/examples/build
# プログラムを実行
LD_LIBRARY_PATH=/usr/local/vsomeip/lib VSOMEIP_CONFIGURATION=sample-vsomeip-tcp-client.json VSOMEIP_APPLICATION_NAME=client-sample ./request-sample

レスポンス側

新たに端末を起動し,以下の手順でNodeB内に入り,プログラムを実行する.

# NodeBに入る
 docker exec -it node_b bash
# 移動
cd /code/examples/build
# プログラムを実行
LD_LIBRARY_PATH=/usr/local/vsomeip/lib VSOMEIP_CONFIGURATION=sample-vsomeip-tcp-service.json VSOMEIP_APPLICATION_NAME=service-sample ./response-sample

実行結果

リクエスト側

root@83a2415c7b4f:/code/examples/build# LD_LIBRARY_PATH=/usr/local/vsomeip/lib VSOMEIP_CONFIGURATION=sample-vsomeip-tcp-client.json VSOMEIP_APPLICATION_NAME=client-sample ./request-sample
2020-10-08 19:26:28.407884 [info] Parsed vsomeip configuration in 2ms
2020-10-08 19:26:28.418099 [info] Using configuration file: "sample-vsomeip-tcp-client.json".
2020-10-08 19:26:28.428345 [info] Initializing vsomeip application "client-sample".
2020-10-08 19:26:28.431845 [info] Instantiating routing manager [Host].
2020-10-08 19:26:28.432951 [info] create_local_server Routing endpoint at /tmp/vsomeip-0
2020-10-08 19:26:28.433706 [info] Service Discovery enabled. Trying to load module.
2020-10-08 19:26:28.436601 [info] Service Discovery module loaded.
2020-10-08 19:26:28.437625 [info] Application(client-sample, 1343) is initialized (11, 100).
Client settings [protocol=UDP:quiet=false:cycle=1000]
2020-10-08 19:26:28.438473 [info] Starting vsomeip application "client-sample" (1343) using 2 threads I/O nice 255
2020-10-08 19:26:28.440177 [info] shutdown thread id from application: 1343 (client-sample) is: 7f4c485cf700 TID: 786
2020-10-08 19:26:28.440305 [info] main dispatch thread id from application: 1343 (client-sample) is: 7f4c48dd0700 TID: 785
2020-10-08 19:26:28.444401 [info] Watchdog is disabled!
Service [1234.5678] is NOT available.
Service [1235.5678] is NOT available.
2020-10-08 19:26:28.445496 [info] io thread id from application: 1343 (client-sample) is: 7f4c4963cec0 TID: 783
2020-10-08 19:26:28.445597 [info] REQUEST(1343): [1234.5678:255.4294967295]
2020-10-08 19:26:28.447134 [info] Listening at /tmp/vsomeip-1343
2020-10-08 19:26:28.445702 [info] io thread id from application: 1343 (client-sample) is: 7f4c475cd700 TID: 788
2020-10-08 19:26:28.450898 [info] vSomeIP 3.1.16.1 | (default)
2020-10-08 19:26:28.451717 [info] Network interface "eth0" state changed: up
2020-10-08 19:26:28.453084 [info] Route "default route (0.0.0.0/0) if: eth0 gw: 192.168.100.1" state changed: up
2020-10-08 19:26:28.453754 [info] udp_server_endpoint_impl: SO_RCVBUF is: 212992
2020-10-08 19:26:28.455182 [info] udp_server_endpoint_impl: SO_RCVBUF (Multicast) is: 212992
2020-10-08 19:26:28.456837 [info] SOME/IP routing ready.
Service [1235.5678] is available.
Service [1234.5678] is available.
2020-10-08 19:26:30.398135 [error] Routing info for remote service could not be found! (1343): [1234.5678.0421] 0001
Client/Session [1343/0001] sent a request to Service [1234.5678]
2020-10-08 19:26:36.405809 [warning] Didn't receive a multicast SD message for 2200ms.
2020-10-08 19:26:36.409495 [info] udp_server_endpoint_impl: SO_RCVBUF (Multicast) is: 212992
2020-10-08 19:26:38.453815 [info] vSomeIP 3.1.16.1 | (default)
Service [1234.5678] is NOT available.
Service [1235.5678] is NOT available.
2020-10-08 19:26:42.819227 [warning] Didn't receive a multicast SD message for 2200ms.
2020-10-08 19:26:42.823042 [info] udp_server_endpoint_impl: SO_RCVBUF (Multicast) is: 212992
2020-10-08 19:26:45.827210 [warning] Didn't receive a multicast SD message for 2200ms.
2020-10-08 19:26:45.830797 [info] udp_server_endpoint_impl: SO_RCVBUF (Multicast) is: 212992
2020-10-08 19:26:47.834375 [warning] Didn't receive a multicast SD message for 2200ms.
2020-10-08 19:26:47.838612 [info] udp_server_endpoint_impl: SO_RCVBUF (Multicast) is: 212992
2020-10-08 19:26:48.457299 [info] vSomeIP 3.1.16.1 | (default)
2020-10-08 19:26:49.841712 [warning] Didn't receive a multicast SD message for 2200ms.
2020-10-08 19:26:49.844287 [info] udp_server_endpoint_impl: SO_RCVBUF (Multicast) is: 212992
Service [1235.5678] is available.
Service [1234.5678] is available.
2020-10-08 19:26:50.473382 [error] Routing info for remote service could not be found! (1343): [1234.5678.0421] 0002
Client/Session [1343/0002] sent a request to Service [1234.5678]
^C2020-10-08 19:26:54.118953 [info] RELEASE(1343): [1234.5678]
2020-10-08 19:26:54.125003 [error] Routing info for remote service could not be found! (1343): [1234.5678.0421] 0003
Client/Session [1343/0003] sent a request to Service [1234.5678]
^C2020-10-08 19:26:54.406298 [info] RELEASE(1343): [1234.5678]
terminate called after throwing an instance of 'std::system_error'
  what():  Resource deadlock avoided
Aborted

「Client/Session [1343/0001] sent a request to Service [1234.5678]」とあるから,リクエストを送信できている,と判断する.

レスポンス側

root@b455a5072adb:/code/examples/build# LD_LIBRARY_PATH=/usr/local/vsomeip/lib VSOMEIP_CONFIGURATION=sample-vsomeip-tcp-service.json VSOMEIP_APPLICATION_NAME=service-sample ./response-sample
2020-10-08 19:26:30.740818 [info] Parsed vsomeip configuration in 3ms
2020-10-08 19:26:30.750707 [info] Using configuration file: "sample-vsomeip-tcp-service.json".
2020-10-08 19:26:30.760663 [info] Initializing vsomeip application "service-sample".
2020-10-08 19:26:30.761505 [info] Instantiating routing manager [Host].
2020-10-08 19:26:30.762668 [info] create_local_server Routing endpoint at /tmp/vsomeip-0
2020-10-08 19:26:30.764036 [info] Service Discovery enabled. Trying to load module.
2020-10-08 19:26:30.767126 [info] Service Discovery module loaded.
2020-10-08 19:26:30.767859 [info] Application(service-sample, 1277) is initialized (11, 100).
Static routing OFF
2020-10-08 19:26:30.768479 [info] Starting vsomeip application "service-sample" (1277) using 2 threads I/O nice 255
2020-10-08 19:26:30.770348 [info] main dispatch thread id from application: 1277 (service-sample) is: 7fc1e1ac7700 TID: 788
2020-10-08 19:26:30.772081 [info] Watchdog is disabled!
2020-10-08 19:26:30.776807 [info] io thread id from application: 1277 (service-sample) is: 7fc1e2333ec0 TID: 786
2020-10-08 19:26:30.777148 [info] io thread id from application: 1277 (service-sample) is: 7fc1dbfff700 TID: 791
2020-10-08 19:26:30.778769 [info] vSomeIP 3.1.16.1 | (default)
2020-10-08 19:26:30.779538 [info] Network interface "eth0" state changed: up
Application service-sample is registered.
2020-10-08 19:26:30.770877 [info] shutdown thread id from application: 1277 (service-sample) is: 7fc1e12c6700 TID: 789
2020-10-08 19:26:30.780408 [info] Route "default route (0.0.0.0/0) if: eth0 gw: 192.168.100.1" state changed: up
2020-10-08 19:26:30.781873 [info] OFFER(1277): [1234.5678:0.0] (true)
2020-10-08 19:26:30.783546 [info] udp_server_endpoint_impl: SO_RCVBUF is: 212992
2020-10-08 19:26:30.784057 [debug] Joining to multicast group 224.244.224.245 from 192.168.100.3
2020-10-08 19:26:30.784525 [info] udp_server_endpoint_impl: SO_RCVBUF (Multicast) is: 212992
2020-10-08 19:26:30.784910 [info] SOME/IP routing ready.
2020-10-08 19:26:30.788736 [info] Listening at /tmp/vsomeip-1277
2020-10-08 19:26:30.790500 [info] OFFER(1277): [1235.5678:0.0] (true)
2020-10-08 19:26:30.791146 [info] udp_server_endpoint_impl: SO_RCVBUF is: 212992
2020-10-08 19:26:40.781679 [info] vSomeIP 3.1.16.1 | (default)
2020-10-08 19:26:40.804810 [info] STOP OFFER(1277): [1234.5678:0.0] (true)
2020-10-08 19:26:40.807028 [info] STOP OFFER(1277): [1235.5678:0.0] (true)
2020-10-08 19:26:50.784224 [info] vSomeIP 3.1.16.1 | (default)
2020-10-08 19:26:50.819593 [info] OFFER(1277): [1234.5678:0.0] (true)
2020-10-08 19:26:50.823144 [info] OFFER(1277): [1235.5678:0.0] (true)
2020-10-08 19:26:50.827366 [info] udp_server_endpoint_impl: SO_RCVBUF is: 212992
^C2020-10-08 19:26:55.620901 [info] STOP OFFER(1277): [1234.5678:0.0] (true)
2020-10-08 19:26:55.621967 [info] STOP OFFER(1277): [1235.5678:0.0] (true)
^C2020-10-08 19:26:55.587222 [info] STOP OFFER(1277): [1234.5678:0.0] (true)
2020-10-08 19:26:55.588255 [info] STOP OFFER(1277): [1235.5678:0.0] (true)
terminate called after throwing an instance of 'std::system_error'
  what():  Resource deadlock avoided
Aborted

リクエスト側のプログラムがそれっぽく動作していることは確認できた.一方,レスポンス側のプログラムがレスポンスを返せていない気がする.

この点については,通信シーケンスやjsonのconfig情報を確認した上で再度チェックしたいと思う.(いつになることやら)

PowerShell メッセージボックスの利用

どうも,筆者です.

Power Shellでメッセージボックスを利用したい状況が発生した.

ここでは,メッセージボックスの利用方法を備忘録として残しておく.

準備

Power Shellでメッセージボックスを利用する際は,最初に以下の記述が必要となる.

# アセンブリの読み込み
Add-Type -AssemblyName System.Windows.Forms

メッセージボックスのフォーマット

メッセージボックスのフォーマットは以下のようになる.

[System.Windows.Forms.MessageBox]::Show('表示したいメッセージ', 'タイトル', 'ボタンタイプ', 'ボタンの種類')

利用例

ここでは,「テキストファイルを削除する際に確認用のポップアップ(YesNoのメッセージボックス)を表示し,処理結果のポップアップ(OKのメッセージボックス)を表示する」という処理をPower Shellで実現する.

以下のようなスクリプトを書くことで,上記の処理を実現できる.

# アセンブリの読み込み
Add-Type -AssemblyName System.Windows.Forms

# メッセージボックスの作成
$msgbox_input = [System.Windows.Forms.MessageBox]::Show('.txtファイルを削除しますか?', '削除確認', 'YesNo', 'Question')

# 条件処理
switch ($msgbox_input) {
    'Yes' {
        # 強制的に削除
        Remove-Item .\*.txt -Force

        [System.Windows.Forms.MessageBox]::Show('削除しました', '結果', 'OK', 'Information')
    }
    'No' {
        # 何もしない
        [System.Windows.Forms.MessageBox]::Show('キャンセルしました', '結果', 'OK', 'Exclamation')
    }
}

おまけ

Power Shellのスクリプトを呼び出すbatファイルのサンプルを以下に示す.ここで,上記のスクリプトを「sample.ps1」として保存したと仮定する.

@echo off
cd /d %~dp0

rem セキュリティポリシーを指定して実行
powershell -ExecutionPolicy Unrestricted .\sample.ps1