コーヒー飲みながら仕事したい

仕事で使う技術的なことの備忘録とか


Wordpress に引っ越しました!

Protocol Buffers の C# 版で遊んでみる

Protocol Buffers のC#

有名どころでは、以下の2つがあるようです。

※ 追記:前者でも .proto ファイルを使用することができるみたいです。

今回の私が手掛ける案件では、後者のほうが適する(CのサービスとC#のサービスがやりとりする)ので、ここでは Google.Protobuf を主に取り上げます。

参考サイト

tnakamura.hatenablog.com

C# 版 protobuf (Google.Protobuf) の導入

githubのReadmeに書かれている手順で導入していきます。

条件

以下が条件です。

  • Visual Studio 2012 意向であること
  • .NET4.5 以降または .NET Core であること

Nuget

Google.Protobuf を使用するだけなら、 Google.Protobuf を Nuget すればよいです。
しかし、それに加えて .proto ファイルを使用してクラスファイルを生成するならば、 Google.Protobuf.Tools も Nuget する必要があります。

Google.Protobuf はライブラリなのだが、 Google.Protobuf.Tools はライブラリではなく、バイナリ(ptoroc.exe)が入っています。
ちなみに、 Nuget した際のダウンロード先は、私の場合はC:\Users\XXX\.nuget\packages\google.protobuf.tools\3.5.1\tools でした。
ソリューションファイル内にダウンロードされているものだと思っていたので、ちょっとはまってしまいました。

Google.Protobuf でチュートリアルする

とりあえず、公式のチュートリアルを実行してみます。
公式は英語なので、備忘録として意訳したやつを残しておきます。

.proto ファイルの用意

とりあえずチュートリアルで示されている addressbook.proto を使用します。これはgithubに掲載されているのだが、このまま使用するとエラーになる(import "google/protobuf/timestamp.proto" なんてねーよって言われる)ので、修正したのを↓に載せときます。

// [START declaration]
syntax = "proto3";
package tutorial;

// [END declaration]

// [START java_declaration]
option java_package = "com.example.tutorial";
option java_outer_classname = "AddressBookProtos";
// [END java_declaration]

// [START csharp_declaration]
option csharp_namespace = "Google.Protobuf.Examples.AddressBook";
// [END csharp_declaration]

// [START messages]
message Person {
  string name = 1;
  int32 id = 2;  // Unique ID number for this person.
  string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    string number = 1;
    PhoneType type = 2;
  }

  repeated PhoneNumber phones = 4;
}

// Our address book file is just one of these.
message AddressBook {
  repeated Person people = 1;
}
// [END messages]

.proto ファイルからクラスファイルを生成する

Nuget した Google.Protobuf.Tools 内に含まれる tools\windows_x64\protoc.exe を使用して、addressbook.protoシリアライズ/デシリアライズ用のクラスファイルを生成しあmす。

protoc -I=$SRC_DIR --csharp_out=$DST_DIR $SRC_DIR/addressbook.proto

上記を実行すると、Addressbook.cs$DST_DIR 内に生成されます。

Addressbook.cs の中身を見ると、なかなかキモくて焦るが、たぶん利用する側は中身を意識する必要はそんなになさそう)

生成されたクラスファイルと Google.Protobuf を使用して、シリアライズ/デシリアライズをやってみる

チュートリアルを参考に、以下のように動作確認用の Program.cs を作成して実行してみます。
実行結果、正しく動作していることが確認できました。

using System;
using System.IO;
using System.Text;
using Google.Protobuf;
using Google.Protobuf.Examples.AddressBook; // protoc.exeにより自動生成されたクラスの名前空間
using static Google.Protobuf.Examples.AddressBook.Person.Types; // C# 6 の書き方で、クラス内クラスを省略形式で記述することができるようになる(protobufとは関係なし)

namespace ProtobufCsharp
{
    class Program
    {
        static void Main(string[] args)
        {
            // AddressBook.csで定義されているPresonクラスを実体化する
            Person person = new Person
            {
                Id = 1234,
                Name = "Yamada Tarou",
                Email = "yamada@sample.com",
                Phones = { new PhoneNumber { Number = "555-4321", Type = PhoneType.Home },
                    new PhoneNumber { Number = "222-1111", Type = PhoneType.Work } }
            };

            // 文字列にシリアライズ
            var data = Serialize(person);

            // シリアライズした文字列を読み込んでデシリアライズする
            var someone = Deserialize<Person>(data);

            // 動作確認
            Console.WriteLine($"Id:{someone.Id}, Name:{someone.Name}, Email:{someone.Email}, " +
                $"Phones[0](Number:{someone.Phones[0].Number}, Type:{someone.Phones[0].Type}), " +
                $"Phones[1](Number:{someone.Phones[1].Number}, Type:{someone.Phones[1].Type})");

            Console.ReadKey();
        }

        static byte[] Serialize<T>(T obj) where T : IMessage<T>
        {
            using (var stream = new MemoryStream())
            {
                obj.WriteTo(stream);
                return stream.ToArray();
            }
        }

        static T Deserialize<T>(byte[] data) where T : IMessage<T>, new()
        {
            var parser = new MessageParser<T>(() => new T());
            return parser.ParseFrom(new MemoryStream(data));
        }
    }
}

解説

  • WriteTo(stream) メソッドで、Stream 型にシリアライズすることができる
  • Parser.ParseFrom(stream) メソッドで、Stream 型からデシリアライズすることができる
  • 実際、ネットワーク間でメッセージのやり取りをする場合は、文字列が都合がいい場合が多いので、その場合は MemoryStream 型を byte 配列に変換すればよい

とりあえず思ったより簡単に実行できました。
ただし、Stream 型を使用するシリアライズ/デシリアライズはちょっと面倒だ。直に byte 配列にできればいいのに。
ちょっと調査します。

直に byte 配列にシリアライズ/デシリアライズするようにサンプルを変更してみました。たぶんこれでいける。

Visual Studio 2017 で protobuf-c を試してみる

前回の続き。

tassi-yuzukko.hatenablog.com

もろもろの準備がやっとできたので、 Visual Studio 2017 で protobuf-c を試してみる。

前準備

あらかじめ下記内容で amessage.proto を用意しておく(前回生成済み)

syntax = "proto3";

message AMessage {
  int32 a=1; 
  int32 b=2;
}

そして、protoc-c --c_out=. amessage.proto で、以下のファイルを生成しておく(これも前回実施済み)

  • amessage.pb-c.c
  • amessage.pb-c.h

ソリューションの作成

上記のファイル2つと、 protobuf-c.c および protobuf-c.h をソリューションフォルダ内につっこむ。

この際、便宜上、以下を変更した。

amessage.pb-c.h

7:  --- #include <protobuf-c/protobuf-c.h>
7:  +++ #include "protobuf-c.h"    // protobuf-c.hをローカルに置いたため & <>の括弧ではアクセスできないため

protobuf-c.c

316:  --- return (-(uint32_t)v) * 2 - 1;
316:  +++ return ((uint32_t)(-v)) * 2 - 1;    // Visual Studio コンパイル時にエラーとなったため(符号なし型にマイナスをつけることができないみたい)

381:  --- return (-(uint64_t)v) * 2 - 1;
381:  +++ return ((uint64_t)(-v)) * 2 - 1;    // Visual Studio コンパイル時にエラーとなったため(符号なし型にマイナスをつけることができないみたい)

2413:  --- return -(v >> 1) - 1;
2413:  +++ return -1 * (v >> 1) - 1;    // Visual Studio コンパイル時にエラーとなったため(符号なし型にマイナスをつけることができないみたい)

2457:  --- return -(v >> 1) - 1;
2457:  +++ return -1 * (v >> 1) - 1;    // Visual Studio コンパイル時にエラーとなったため(符号なし型にマイナスをつけることができないみたい)

3147:  --- tmp.length_prefix_len = pref_len;
3147:  +++ tmp.length_prefix_len = (uint8_t)pref_len;    // 警告が出たので一応

注意

Visual Studio の環境では、これらのファイルをコンパイル対象とするために、明示的にソリューション(というかプロジェクト)構成配下に登録する必要がある。

Simple complete example チュートリアル実行

基本的に、Examples · protobuf-c/protobuf-c Wiki · GitHub を参照して、 protobuf-c の Simple complete example チュートリアルを実行してみる。

しかし以下を変更してやってみる。

結果、以下のようなファイルを用意した。

// AMessageSerialize.h

#pragma once
#include <windows.h>

BOOL AMessageSerialize(int argc, const char * argv[]);
// AMessageSerialize.c

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include "amessage.pb-c.h"
#include "AMessageSerialize.h"

static void MyWriteFile(void const * buf, size_t len, const char* filename);

BOOL AMessageSerialize(int argc, const char * argv[])
{
    AMessage msg = AMESSAGE__INIT; // AMessage
    void *buf;                     // Buffer to store serialized data
    unsigned len;                  // Length of serialized data

    if (argc != 2 && argc != 3)
    {   // Allow one or two integers
        fprintf(stderr, "usage: amessage a [b]\n");
        return FALSE;
    }

    msg.a = atoi(argv[1]);
    msg.b = atoi(argv[2]);
    len = amessage__get_packed_size(&msg);

    buf = malloc(len);
    amessage__pack(&msg, buf);

    fprintf(stderr, "Writing %d serialized bytes\n", len); // See the length of message
    MyWriteFile(buf, len, "test.txt"); // Write to stdout to allow direct command line piping

    free(buf); // Free the allocated serialized buffer
    return TRUE;
}

static void MyWriteFile(void const * buf, size_t len, const char* filename)
{
    FILE* fp;

    fopen_s(&fp, filename, "wb");
    if (fp == NULL) {
        fprintf(stderr, "failed to write file.");
        goto END;
    }

    fwrite(buf, len, 1, fp);

END:
    fclose(fp);

    return;
}
// AMessageDeserialize.h

#pragma once
#include <windows.h>

BOOL AMessageDeserialize();
// AMessageDeserialize.c

#pragma once

#include <stdio.h>
#include <stdlib.h>
#include "amessage.pb-c.h"
#include "AMessageDeserialize.h"
#define MAX_MSG_SIZE 1024

static size_t
read_buffer(unsigned max_length, uint8_t *out, const char* filename)
{
    size_t cur_len = 0;
    size_t nread;
    FILE* fp;

    fopen_s(&fp, filename, "rb");
    if (fp == NULL) {
        fprintf(stderr, "failed to read file.");
        goto END;
    }

    while ((nread = fread(out + cur_len, 1, max_length - cur_len, fp)) != 0)
    {
        cur_len += nread;
        if (cur_len == max_length)
        {
            fprintf(stderr, "max message length exceeded\n");
            exit(1);
        }
    }

END:
    fclose(fp);

    return cur_len;
}


BOOL AMessageDeserialize()
{
    AMessage *msg;

    // Read packed message from standard-input.
    uint8_t buf[MAX_MSG_SIZE];
    size_t msg_len = read_buffer(MAX_MSG_SIZE, buf, "test.txt");

    // Unpack the message using protobuf-c.
    msg = amessage__unpack(NULL, msg_len, buf);
    if (msg == NULL)
    {
        fprintf(stderr, "error unpacking incoming message\n");
        return FALSE;
    }

    // display the message's fields.
    printf("Received: a=%d  b=%d \n", msg->a, msg->b);  // required field

    // Free the unpacked message
    amessage__free_unpacked(msg, NULL);
    return TRUE;
}
// main.c

#pragma once

#include <stdio.h>
#include "AMessageSerialize.h"
#include "AMessageDeserialize.h"

int main(int argc, const char * argv[])
{
    AMessageSerialize(argc, argv);
    AMessageDeserialize();

    system("pause");

    return 0;
}

実行結果

引数を 10 2 で実行してみると、以下になった。

Writing 4 serialized bytes
Received: a=10  b=2
続行するには何かキーを押してください . . .

んーたぶんできてるっぽい。
とりあえず目的達成。シリアライズとデシリアライズの方法も直感的だし、C言語でここまでできるのはかなり魅力的だなーと思いました。

ソースコード

一応、ソースコードを載せとく。

protobuf-c で今度こそ遊んでみる(proto2とproto3の違い編)

あらすじ

もともと軽い気持ちで Protocol Buffers のC言語版を遊んでみようと思っていたら、意図せず Docker を巻き込んだ一大イベントに発展した。

やっとこさ準備ができたので、楽しく遊ぼうとしていた。が、しかし・・・

protocol buffers のバージョン2とバージョン3は互換性がない件について

protobuf-c の wikiを読みながらチュートリアルに取り組んでみた。

amessage.proto という名前で以下の内容のファイルを作る。

message AMessage {
  required int32 a=1; 
  optional int32 b=2;
}

で、さっそく protobuf-c を実行させて AMessage 構造体のシリアライザーとデシリアライザーを作ろうと以下を実行した。

root@e834aae66aee:/work/ProtocolBuffersTest# protoc-c --c_out=. amessage.proto
[libprotobuf WARNING google/protobuf/compiler/parser.cc:546] No syntax specified for the proto file: amessage.proto. Please use 'syntax = "proto2";' or 'syntax = "proto3";' to specify a syntax version. (Defaulted to proto2 syntax.)

なんか警告が出る!
直訳すると、「 proto2 と proto3 のどっちで動作させるかちゃんと明記('syntax = "proto2";' か 'syntax = "proto3";')してくれ。じゃないと proto2 で動作するよ。」って感じだと思う。
なんとなくだけど、新しいほうがいいと思うので、amessage.proto を以下のように変更してみた。

syntax = "proto3";

message AMessage {
  required int32 a=1; 
  optional int32 b=2;
}

で、実行するとエラーになる・・・

root@e834aae66aee:/work/ProtocolBuffersTest# protoc-c --c_out=. amessage.proto
amessage.proto:5:12: Explicit 'optional' labels are disallowed in the Proto3 syntax. To define 'optional' fields in Proto3, simply remove the 'optional' label, as fields are 'optional' by default.

調べてみると、どうやら proto2 と proto3 で protoファイルの記法がかわったとのこと。
具体的には、proto3 では requiredoptional が削除されたらしい。
なんで?って感じだけど、以下の stackoverflow に質問と回答があったので、一応載せとく。よく読んでないけど、拡張性を考慮するとそれらを削除するという流れになったそうだ。

stackoverflow.com

protocol buffers バージョン3を選択する

ということで、再々度 amessage.proto を変更する。

syntax = "proto3";

message AMessage {
  int32 a=1; 
  int32 b=2;
}

これで、 protoc-c --c_out=. amessage.proto が正常に動作して、以下のファイルが出力された。

  • amessage.pb-c.c
  • amessage.pb-c.h

引き続き、wiki の Examples に従ってチュートリアルしてみるけど、まんま wiki の通りになるので割愛します。

Protobuf-c を Docker 上の Ubuntu 環境でインストールする

あらすじ

前回、 protobuf を Docker 上の Ubuntu 環境でインストールした。

tassi-yuzukko.hatenablog.com

今回は、いよいよ protobuf の C言語版である protobuf-c をインストールする。

protobuf-c をインストールするまでの手順

基本的には protobuf と同様に、以下の Readme に従う。

github.com

git hub からリポジトリをクローンする

こちらからクローン。詳細は省略します。

コンパイル/インストールする

Readme に書いてある通り、./autogen.sh && ./configure && make && make install を実行すればコンパイル&インストールができるらしい。

ちなみに、前提として以下の記事の通り、 protobuf-c をコンパイルするための Ubuntu の環境は構築済みとする。

tassi-yuzukko.hatenablog.com

tassi-yuzukko.hatenablog.com

補足

なんと、リリース版なのにコンパイルエラーになる。(protobuf-c ver1.30)

In file included from protoc-c/c_file.cc:64:0:
./protoc-c/c_file.h:107:3: error: 'vector' does not name a type
   vector<string> package_parts_;

調べてみると、既知の問題らしく、 issue に解決策が載っていた。
どうやら、 vectorstd::vector に、 pairstd::pair に置換すればよいとのこと。

github.com

理由は英語で解説してるっぽい人がいたけど、google先生に翻訳してもらってもよくわからん・・・

とりあえず言われた通り置換すると、一応コンパイル通りました。

動作確認

protoc-c --version を実行し、以下が出たたらOK。

root@e834aae66aee:/work/protobuf-c# protoc-c --version
protobuf-c 1.3.0
libprotoc 3.5.1

いやーしかし、リリース版がコンパイル通らないって・・・なんかこれ心配になってきたぞ・・・

次回はいよいよ、 protobuf-c を使って遊んでみる!

Protobuf を Docker 上の Ubuntu 環境でインストールする

あらすじ

前回の続き

tassi-yuzukko.hatenablog.com

今までの流れの概略

  • protobuf-c をコンパイルしようと思ったら Windows 上ではうまくいかなかった
  • Ubuntu 環境だったらうまくいくのではと思い、 Docker (Docker ToolBox)を導入してみた
  • Ubuntu のイメージを、 protobuf-c コンパイル用にカスタマイズするために Dockerfile を用意した
  • →protobuf-c をコンパイルするために、本家 Protobuf が必要なのだが、 Ubuntu 用のパッケージはバージョンが古い(protobuf ver2.6.1)。protobuf-c ver1.30 に互換性問題があり、 protobuf ver3.X 以降でないと、 protobuf-c をコンパイルできない
  • →protobuf ver3.X(最新版)を自分でコンパイル/インストールする

今回の目標

ということで、今回は本家 protobuf ver3.X をインストールする

protobuf をインストールするまでの手順

基本的には以下の Readme に従う。

github.com

git hub からリポジトリをクローンする

git hub のリポジトリからクローンする。

root@e834aae66aee:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  work
root@e834aae66aee:/# cd work
root@e834aae66aee:/work# git clone https://github.com/google/protobuf.git
Cloning into 'protobuf'...
remote: Counting objects: 50405, done.
remote: Compressing objects: 100% (10/10), done.
remote: Total 50405 (delta 5), reused 6 (delta 3), pack-reused 50392
Receiving objects: 100% (50405/50405), 44.17 MiB | 126.00 KiB/s, done.
Resolving deltas: 100% (33940/33940), done.
Checking connectivity... done.
Checking out files: 100% (1952/1952), done.

補足

一応、データ永続化用の共有フォルダにクローンすると、Windows であれば tortoise git とかの GUIで git 操作でき、ubuntuwindows のいいとこどりができる。
ちなみに、こういう永続化領域を Data Volume というらしい。

コンフィグスクリプトを生成する

クローンしたら、 ./autogen.sh を実行しなければいけないらしい。

root@e834aae66aee:/work# cd protobuf
root@e834aae66aee:/work/protobuf# ./autogen.sh

補足

Readme に You can skip this step if you are using a release package (which already contains gmock and the configure script). とあるので、もしかしたらコンパイルするだけなら上記コンフィグスクリプトは不要かもしれない。

コンパイルとインストール

Readmeによると、以下を実行するとのこと。

$ ./configure
$ make
$ make check
$ sudo make install
$ sudo ldconfig

Readmeには、環境によっては追加でいろいろやらないとコンパイルが通らないことがあるとのことだけど、私の環境では上記コンパイル/インストールが成功したっぽい。

補足

make と make check は激遅です。無限ループしてるんじゃないかってくらい、同じようなビルドログが出力され続けて終わりません。私の環境でそれぞれ20分以上かかりました。

インストール確認

protoc --version が正常にできればとりあえずインストールはOKと思われる。

root@e834aae66aee:/work/protobuf# protoc --version
libprotoc 3.5.1

とりあえず protobuf のインストールまでできた。
次回は protobuf-c のインストールについてまとめる。


別のインストール方法

githububuntu で protobuf ver3.X をインストールすることを題材として issue を見つけた。

gist.github.com

これによると、 https://github.com/google/protobuf/releases/download/v3.4.0/protoc-3.4.0-linux-x86_64.zip でも入手してインストールできるみたい。
一応備忘録として残しておく。

Dockerfile を使って、自分用の Ubuntu の Docker イメージを作成する

前回の続き。

tassi-yuzukko.hatenablog.com

今回の目的

docker pull ubuntuで最新版のubuntuイメージを取得することはできる。
しかし、その場合、 sudoすら入っていない状態なので、一つずつ apt-get で環境整備する必要が出てくる。 そこで、Dcokerfile を使用して楽をする。

Dockerfile とは

イメージのカスタマイズをスクリプトで実現することができる。
Dockerfile を使用することで、物理的に異なるデバイスでも、同一の環境をすぐ用意できるようになる。たぶん。

Ubuntu 用の Dockerfile 導入手順

参考

前提

そもそも Docker を導入した最終目的は protobuf-cで遊ぶためのコンパイル環境を用意することである。
そのため、 Ubuntu 用の Dockerfile も protobuf-c のコンパイルのためにカスタマイズする。

  • protobuf-c をコンパイルするために必要なもの一覧
    • sudo
    • autoconf
    • automake
    • libtool
    • curl
    • make
    • g++
    • unzip
    • pkg-config
    • protobuf(後述の注意の通り、apt-getで取得するのはNG)
  • あと、あれば便利なもの一覧

注意:protobuf-c と protobuf の互換性問題

現状、protobuf-c の最終リリース版(protobuf-c Ver1.30)自体に、本家 protobuf との互換問題があるらしい。
(protobuf Ver3.00 以上を用意しないと protobuf-c がコンパイルできない。しかし、Ubuntu 用の apt-get では protobuf のバージョンがVer2.6X らしいので、普通に本家 protobuf を用意するのではなく、自前で用意する必要がある)

上記を踏まえて Dockerfile を作る

そもそも、Dockerfileの置き場所はどこが適切なのか調べたが、ぱっと出てこない。
たぶん、どこでもいいような気がするので、今回はDocker ToolBox のルートパスである C:\Program Files\Docker Toolbox 直下に置いてみる。
Windows 10 では Program Files 内に直接ファイルを作ることはできないので、℃っか違うところで作って move する)

ファイル名は、まんまDockerfile (拡張子なし)でたぶんOK。

ファイルの中身は以下のようにしてみた。

#利用するUbuntuのイメージ
FROM ubuntu:14.04

#プロキシ設定が必要な場合のみ
#ENV https_proxy=XXX
#ENV http_proxy=XXX

#各種インストール
RUN apt-get update
#protobuf はあえてインストールしない
RUN apt-get install -y sudo autoconf automake libtool curl make g++ unzip pkg-config wget git

Dockerfile をビルド

docker build -t ubuntu1404 . でビルドする。(-t はタグ名なので必須だが任意の文字列)

イメージの取得も行うため、結構時間かかる。

追記

しかも、私の環境では powershell の描画更新がバグって

debconf: unable to initialize frontend: Dialog
debconf: (TERM is not set, so the dialog frontend is not usable.)
debconf: falling back to frontend: Readline
debconf: unable to initialize frontend: Readline
debconf: (This frontend requires a controlling tty.)
debconf: falling back to frontend: Teletype

とか出たりしたけど、気にしないでおこう・・・

さらに追記

さらに私の環境ではビルドが終了すると、上記の描画問題に加え、以下の警告が表示された。

SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host. All files and directories added to build context will have '-rwxr-xr-x' permissions. It is recommended to double check and reset permissions for sensitive files and directories.

うーん、大丈夫なのかなぁ。
内容としては「 '-rwxr-xr-x' になってるよ!」ってだけだから問題なさそうだけど。

イメージの確認

docker images でイメージが作成されたことを確認する。

PS C:\Program Files\Docker Toolbox> docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu1404          latest              1d8f1efde705        10 minutes ago      382MB

たぶん入ってるっぽい。

コンテナの起動

docker run -it -v /work:/work ubuntu1404 で起動する。(前回行った共有フォルダのマウントも有効にしている)

Dockerfile によるカスタマイズの確認

とりあえず make あたりを実行すしてみる。

root@8c8f74f92f1a:/# make
make: *** No targets specified and no makefile found.  Stop.

と出て、 make というコマンドを認識してるっぽいので、成功していることがわかる。


とりあえず今回は Dockerfile を使用して、 Ubuntu による protobuf-c のコンパイルの準備までやった。
次回は、protobuf および protobuf-c のコンパイルに焦点を当てて記事を書く。

Docker でホストマシンのストレージ移動と共有フォルダのマウント

Docker ホストマシンのストレージを移動する

イメージを入れる前に、Docker ToolBox を使用している場合は、C:\Users\<ユーザー名>\.docker\machine\machines\<マシン名>に仮想ディスクファイル (.vmdk) が作られるらしい。
私の環境ではCドライブが切迫しているので、取り急ぎDドライブに移動する。

基本的に↓参照でおk。
(注意:VirtualBox立ち上げっぱなしで.vboxファイル編集してもダメ。.vboxファイルは仮想マシン起動時ではなく、VirtualBox本体を立ち上げるときに読み込まれるらしい。

takaya030.hatenablog.com

データを永続化するために、ストレージを共有フォルダ化する

dockerコンテナは、そのままではデータを永続的に保持できないらしい。そのため、共有フォルダを使用して、データ永続化を実現する必要がある。

ぱっと調べた感じ、参考になるのはあったが、Windows野郎の私にとってはsshの手順とかも慣れていないのですんなりいかなかった。ので、備忘録として手順等を残しておく。

1. VirtualBoxに共有フォルダ設定する

とりあえずここではD:\docker\workを共有フォルダにしてみた。 f:id:tassi-yuzukko:20180303232030j:plain f:id:tassi-yuzukko:20180303232036j:plain f:id:tassi-yuzukko:20180303232040j:plain

2. 起動時設定ファイルを作る

Docker Machineの起動時に、共有フォルダが自動でマウントされるように設定ファイルと作る。

  1. docker-machine ssh実行
    • power shell で実行すると文字化けするので、git bash でやった方が良いかも
  2. /var/lib/boot2docker/bootlocal.shに以下のように書いて保存する
    • bash で操作するから、たぶん vi 使わないといけないんだけど、sudo vi /var/lib/boot2docker/bootlocal.shてな感じで sudo が必要
mkdir -p /d/docker/work
mount -t vboxsf -o defaults,iocharset=utf8,uid=1000,gid=50 work /d/docker/work

3. 設定を有効にする

最後にいったんdocker-machine stop defaultした後に再度 docker-machine start default で docker を再起動する。

参考

共有フォルダをマウントしてコンテナを起動する

docker run -it -v /work:/XXX <コンテナ名>:<タグ> で、上述した work のシンボリックリンクの共有フォルダが、 コンテナ上に XXX フォルダとしてマウントされる。

うーん、ややこしいなぁ。