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つ.
Docker Desktop for Windowsのインストール
下記のサイトを参考に,インストールを実施する.
これで,一通り準備が整った.次は,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
格納後のディレクトリ構成は以下のようになる.
./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情報を確認した上で再度チェックしたいと思う.(いつになることやら)