20200316のdockerに関する記事は19件です。

EC-CUBE4 プラグイン開発 ①Dockerで環境構築

概要

EC-CUBE4でプラグインを開発することになった。
プロジェクトの最初から最後まで関わるのは初めてなので、あとで自分が振り返るために考えたことや試したことをどこかに記録しておこうと思った。
あと、忘れても問題ない状況を作って早く忘れてしまいたい。

本記事では、Dockerで開発環境を構築する手順を書く。内容は、他のメンバーに共有するために仕事中に調べてまとめたものを加筆・修正しただけ。
環境構築は、EC-CUBE 4.0 開発者向けドキュメントの通り進めれば簡単に終わる。

目次

EC-CUBE4 プラグイン開発 ①環境構築手順 (本記事)
EC-CUBE4 プラグイン開発 ②プラグイン開発特有のTips (未投稿)
EC-CUBE4 プラグイン開発 ③プラグイン開発を通して得た知識、考えたこと (未投稿)

たぶん3本立てで書きそうな気がする。
SymfonyやEC-CUBE4についていろいろ知ったとはいえ、学んだことのうち、今後のプログラミングに活かせることはたぶん少ない。

動作確認環境

Windows10 Pro
PHPStorm 2019.3.3
Docker Desktop 2.1.0.5
Docker 19.03.5
EC-CUBE 4.0.3
Symfony 3.4
PHP 7.3
MySQL 5.7

Postgresを使用する場合はMySQLと置き換えてください。

環境構築手順

Docker Desktop for Windows/Mac をインストール

既にDockerが使える状態にある場合は次のステップへ。
Docker Desktop for Windows

git configがglobalで core.autocrlf=input になっていることを確認する

既に設定されている場合は次のステップへ。
※他のプロジェクトに影響させたくない場合は、次のステップ「EC-CUBE本体をgit clone」でcloneするときだけglobalの設定を変更し、cloneが終わったら元に戻す。
gitconfig の基本を理解する

理由:

EC-CUBE本体をgit clone

// 任意のディレクトリへ移動
cd xxx
git clone https://github.com/EC-CUBE/ec-cube.git

.envをコピー

cd ec-cube
cp .env.dist .env

.envの内容を書き換える

Mysql、メールデバッグ用サーバを使うため。

# DATABASE_URL=sqlite:///var/eccube.db
DATABASE_URL=mysql://dbuser:secret@mysql/eccubedb
# MAILER_URL=null://localhost
MAILER_URL=smtp://mailcatcher:1025

# 開発者間で暗号処理を統一したい場合は、この値を統一する。テストデータに含まれる暗号化したパスワードなどを共用できる。
ECCUBE_AUTH_MAGIC=xxxxx

docker-compose.ymlを書き換える

①PhpStormのコード補完機能を有効にするため、vender配下をホスト・コンテナ間で同期させる。
(ちなみにvar配下を同期させるとlocalでlogファイルが閲覧できる。しかし、logに吐かれる内容が非常にわかりづらく、ほぼ活用しなかった。また、ホスト・コンテナ間の同期が増えればその分動作が重くなると考え、最終的には同期するのをやめた。)

下記に示す通り、計3行をコメントアウト、または削除する。
docker-compose.yml 15行目~39行目付近 Before

  ### ignore folder volume #####
  var:
    driver: local
  vender:    ★この行を消す★
    driver: local  ★この行を消す★

services:
  ### ECCube4 ##################################
  ec-cube:
    build: 
      context: .
      args:
        # ビルド時のECCubeインストールスクリプトをスキップする場合にtrueを指定する。
        # ビルド時点でDBサーバの起動や接続が出来ない、という場合等にエラーとなるため。
        SKIP_INSTALL_SCRIPT_ON_DOCKER_BUILD: "true"
    ports:
      - 8080:80
      - 4430:443
    volumes:
      - ".:/var/www/html:cached"
      ### 同期対象からコストの重いフォルダを除外 #####################
      - "var:/var/www/html/var"
      - "vender:/var/www/html/vendor" ★この行を消す★
    networks: 
      - backend

docker-compose.yml 15行目~39行目付近 After

  ### ignore folder volume #####
  var:
    driver: local
    ★消した!★
services:
  ### ECCube4 ##################################
  ec-cube:
    build: 
      context: .
      args:
        # ビルド時のECCubeインストールスクリプトをスキップする場合にtrueを指定する。
        # ビルド時点でDBサーバの起動や接続が出来ない、という場合等にエラーとなるため。
        SKIP_INSTALL_SCRIPT_ON_DOCKER_BUILD: "true"
    ports:
      - 8080:80
      - 4430:443
    volumes:
      - ".:/var/www/html:cached"
      ### 同期対象からコストの重いフォルダを除外 #####################
      - "var:/var/www/html/var"
         ★消した!★
    networks: 
      - backend

②Postgresコンテナは利用しないので、次のコードをコメントアウトまたは削除する

  ### Postgres ################################
  postgres:
    image: postgres:10
    environment:
      - POSTGRES_DB=eccubedb
      - POSTGRES_USER=dbuser
      - POSTGRES_PASSWORD=secret
    ports:
      - 15432:5432
    volumes:
      - pg-database:/var/lib/postgresql/data
    networks: 
      - backend

Dockerコンテナを起動

// docker-compose.ymlが存在するディレクトリに移動
cd xxx/ec-cube

docker-compose up -d --build

composer install

docker-compose exec ec-cube composer install

インストールスクリプトを実行する

注意:このスクリプトを実行すると、データやプラグインがすべて初期化される。初回は気にしなくてOKだが、誤って実行して初期化しないように。

docker-compose exec ec-cube bin/console eccube:install

Installer Wizard が立ち上がるので、画面に従ってインストールを実行する。
既に.envを書き換えてあるので、Enter連打して全部OKするだけ。↓こんな感じのログが出る

$ docker-compose exec ec-cube bin/console eccube:install

EC-CUBE Installer Interactive Wizard
====================================

 If you prefer to not use this interactive wizard, define the environment valiables as follows:

  $ export APP_ENV=dev
  $ export APP_DEBUG=1
  $ export DATABASE_URL=database_url
  $ export DATABASE_SERVER_VERSION=server_version
  $ export MAILER_URL=mailer_url
  $ export ECCUBE_AUTH_MAGIC=auth_magic
  ... and more
  $ php bin/console eccube:install --no-interaction


 Database Url [mysql://dbuser:secret@mysql/eccubedb]:
 >

 Mailer Url [smtp://mailcatcher:1025]:
 >

 Auth Magic [xxxxxx]:
 >

 !                                                                                                                      
 ! [CAUTION] Execute the installation process. All data is initialized.                                                 
 !                                                                                                                      

 Is it OK? (yes/no) [yes]:
 >

 Run doctrine:database:create --if-not-exists...
 Database `eccubedb` for connection named default already exists. Skipped.

 Run doctrine:schema:drop --force...

 Dropping database schema...

 [OK] Database schema dropped successfully!


 Run doctrine:schema:create...

 ! [CAUTION] This operation should not be executed in a production environment!

 Creating database schema...

 [OK] Database schema created successfully!


 Run eccube:fixtures:load...
   > Finished Successful!

 Run cache:clear --no-warmup...

 // Clearing the cache for the dev environment with debug
 // true

 [OK] Cache for the "dev" environment (debug=true) was successfully cleared.



 [OK] EC-CUBE installation successful.   

これでlocal環境でEC-CUBE標準サイトが見れる状態になったことを確認する。
フロント側 http://localhost:8080/
管理画面 http://localhost:8080/admin

デフォルトのID/PW 公式サイトのデモサイトと同じ。
ID: admin
PW: password

メールデバッグ用SMTPサーバ http://localhost:1080/

次回以降は、次のコマンドでDockerコンテナを起動/終了する。
※EC-CUBEに限らず、PCシャットダウン時にコンテナを終了しておかないと時々Dockerがバグるので注意。毎日終了する。

docker-compose up -d
docker-compose down

ここまでは、localにEC-CUBE標準サイトが動作する環境を作る手順。
ここから先は、開発するプラグインをEC-CUBEに反映する手順。

開発するプラグイン用のリポジトリをcloneする

予め、開発する開発するプラグイン用のリポジトリを作っておく。

cd xxx/ec-cube/app/Plugin

// 任意のディレクトリ名を指定する。 app/Plugin/SamplePluginというディレクトリ構成になる
git clone https://github.com/xxx/sample_plugin.git ./SamplePlugin

プラグインジェネレータでプラグインの骨組みを自動生成

docker-compose exec ec-cube bin/console eccube:plugin:generate

Consoleに答えてEnterで進む。
プラグインには、nameとcodeを設定できる。
nameは、プラグイン一覧ページで表示されるプラグインの名称。日本語も可らしい。

codeは、コマンドを叩くとき、またはプラグインストアで利用される一意の文字列。命名規則は[a-zA-z_]で、数字は使えない。
(市場に出回っているプラグインのなかで一意のはず。自分たちでしか使わないような独自プラグインの場合は、導入したい市場のプラグインと重複しなければなんでもOK)
このcodeは、コマンドを叩くときに使用する。

$ docker-compose exec ec-cube bin/console eccube:plugin:generate

EC-CUBE Plugin Generator Interactive Wizard
===========================================

 name [EC-CUBE Sample Plugin]:
 > SamplePluginName

 code [Sample]:
 > SamplePluginCode

 ver [1.0.0]:
 >                                            

 [OK] Plugin was successfully created: SamplePluginName SamplePluginCode 1.0.0

これで準備が整った。
骨組みを作った時点でgit pushすれば、他の開発者にも共有できる。
他の開発者がこのプラグインをlocalのEC-CUBEにインストールするには、app/Plugin配下にgit cloneして次の項 開発の流れ(大まかに)プラグインをインストール をすればOK

開発の流れ(大まかに)

  • コードを書く。
  • プラグインをインストール
docker-compose exec ec-cube bin/console eccube:plugin:install --code=Sample

すると、こういう感じのログが出てインストールが完了する。(デバッグモード)
コードにタイポがあったりすると、途中で止まってエラーを吐き出してくれる。

$ docker-compose exec ec-cube bin/console eccube:plugin:install --code=Sample
gen -> /tmp/proxy_VLW2B0Y0vtbO/src/Eccube/Entity/Product.php

 // Clearing the cache for the dev environment with debug true

 [OK] Cache for the "dev" environment (debug=true) was successfully cleared.

 [OK] Installed. 
  • プラグインを有効化する。
docker-compose exec ec-cube bin/console eccube:plugin:enable --code=Sample

こういうログが出て、正常に有効化すればOK。

$ docker-compose exec ec-cube bin/console eccube:plugin:enable --code=Sample
gen -> /var/www/html/app/proxy/entity/src/Eccube/Entity/Product.php

 // Clearing the cache for the dev environment with debug true

 [OK] Cache for the "dev" environment (debug=true) was successfully cleared.           

 [OK] Plugin Enabled.
  • 管理画面/フロント画面で動作確認する。エラーが出ていれば修正する。
  • 適宜commit,pushする。

(必要なら)外部プラグインを開発環境で有効にする

初回のみ

プラグインを探すより、外部プラグインを導入する。
ソースコードを落とす必要があるため、初回は認証コードを発行して画面上でプラグインをインストールする。また、ソースを落としてこないとプラグインのコードが分からず、コマンドを叩けない。(プラグインのコードはcomposer.jsonに記述してある)

※codeが判明しているなら、eccube:plugin:installコマンドでも初回ソースDLは可能かもしれない。
e:p:iコマンドを叩いてかなり待ったが処理が進まない、ということがあったため画面上からインストールするようにしているが、e:p:iコマンドが完了するまで待てば正常にソースDLできたのかも・・・。

初回以降
ソースを落とすことができたら、以降は下記コマンドでインストール、有効化を行う。

// プラグインをインストール
docker-compose exec ec-cube bin/console eccube:plugin:install --code={code}

// インストール後、プラグインを有効化
docker-compose exec ec-cube bin/console eccube:plugin:enable --code={code}

または、ec-cubeコンテナに入ってから

// プラグインをインストール
./bin/console eccube:plugin:install --code={code}

// インストール後、プラグインを有効化
./bin/console eccube:plugin:enable --code={code}

リンク集

EC-CUBE4で開発するなら一度は目を通したほうがよいサイト集。実装に慣れるまではしょっちゅう閲覧していたのでブックマークしている。

EC-CUBE 4.0 開発者向けドキュメント
EC-CUBE 4 Style Guide 開発者向けドキュメントからアクセスできる。フロントのCSSで匙を投げる前に。
EC-CUBE 4の決済プラグインサンプル
4.0(旧3.n)ドキュメント化に向けた情報や実装の参考にしたい情報
EC-CUBE4 デモサイト プラグインで拡張しまくると標準の状態を忘れるので確認用に使ってた。

実装する上で調べたもっと細かな情報は②③を書いたときにまとめる。

EC-CUBE4 プラグイン開発 ②プラグイン開発特有のTips (未投稿)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

犬でもわかるDocker導入手順 for Mac in 2020

初めに

当方はレガシーな環境からの脱却を試みる若輩ソフトウェアデベロッパーであり、業務でDockerを使用した経験はない。
当記事はDocker入門者の私が備忘録的に書き記すものであり、あわよくば他の入門者の一助になればと思っている。
その為深い知識の説明はしないし、微妙なニュアンスの違いには目を瞑っていただきたい。
(ただ、気を付けていますが明らかな間違いは他の方の妨害にもなり得るのでご指摘ください。。)

Dockerとは

チーム内での環境差異による不具合などを起こらなくしてくれる物。
「イメージ」と呼ばれる開発環境プリセットのような物を使用することで、そのイメージを使用して作成したアプリは、別環境で同様のイメージを使って環境構築すれば動く。便利!!
わかりやすく言うと(多分ちょっと違うけど)開発環境をUSBに入れてシェアできるみたいな物だと思う。

環境構築

Dockeの説明についてはもっと死ぬほどわかりやすいものがインターネットの海には大量に存在するので、ここからは知識を入れずにとにかく脳死で環境構築したい方のために手順を紹介する。

と言っても、Hello,World!を出力するところまでなので手順というほどのものは存在しない。
本当に犬でもできるレベルである。

Docker for Macのダウンロード

まず、今からDockerを使用する場合、何をダウンロードするかを悩む必要はない。
WindowsならDocker for Windows
MacならDocker for Mac
これだけでいい。
(古いバージョンのOSを使用している場合、少し異なる場合がある。)

ダウンロードはこちらから行える。

接続すると、下記ページが表示されるので、「Get Started」をクリック。

スクリーンショット 2020-03-16 22.03.10(2).png

すると、OSの選択画面になるので使用しているOSに適した方をクリック。

スクリーンショット 2020-03-16 22.03.20(2).png

Dockerのダウンロードページに遷移するので、「Get Docker」をクリックするとダウンロードが開始されます。

スクリーンショット 2020-03-16 22.03.45(2).png

Docker for Macのインストール

ダウンロードが完了したらFinderを開き、ダウンロードディレクトリから「Docker.dmg」ファイルをダブルクリック。

すると下記のような画面が表示されるので、DockerをApplicationsへドラッグ&ドロップ。

スクリーンショット 2020-03-16 22.04.18.png

スクリーンショット 2020-03-16 22.51.27.png

パスワードを求められるので、PCへログインしているユーザーのパスワードを入力すれば、インストールは完了!

Hello,World!

ステータスバーの鯨くんが画像のような状態で停止していればインストールは完了している。
(くるくる動いている場合は大人しく待ちましょう。)

スクリーンショット 2020-03-16 22.56.09.png

停止したらいよいよ皆大好きHello,Worldを試してみる。

terminalを開き、以下のコマンドを実行。

$ docker version

以下のようにバージョン情報が出力されればOK

スクリーンショット 2020-03-16 22.22.09.png

動作確認ができたら下記コマンドでHello,Worldを実行する。

$ docker run hello-world

これは、「Hello,Worldを表示する」というイメージをダウンロードし実行しているということになる。
次のように表示されていれば環境構築はひとまず完了。

スクリーンショット 2020-03-16 23.07.17.png

終わりに

Dockerの導入は個人的にかなりハードルが高いものだと思い込んでいたが、案外すんなり導入できたのでここから実際の開発にも使用していきたい。
実際の開発で詰まった点などはまた記事にまとめていきたいとも思うので、お見かけになった際はマサカリを投げていってください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

エセイー(エセSE)が挑戦する、初めてのDocker

下記サイトに基本的な使い方は書いてある。
https://qiita.com/kariyaitaru/items/83fe1c8c9ed4f8732a63

下記サイトを参考に、dockerhubよりデータを取得する。
https://kitsune.blog/docker-install

docker run -d -p 8080:80 --name nginx nginx

nginxにアクセスする。

http://localhost:8080

上記コンテナを停止・起動する。

# コンテナを停止
$ docker stop nginx
nginx

# コンテナを起動
$ docker start nginx
nginx

次に、コンテナからイメージを作成してみる。以下は「https://kitsune.blog/docker-comman」を参照している。

  1. Dockerベースイメージの取得
  2. Dockerコンテナの起動
  3. Dockerコンテナに変更を加える
  4. Dockerイメージの作成

Dockerイメージの確認

C:\Users\XXXXX>docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              6678c7c2e56c        11 days ago         127MB

Docker Hubからベースイメージを検索するには、「docker search」コマンドを実行します。

C:\Users\XXXXX>docker search centos
NAME                               DESCRIPTION                                     STARS               OFFICIAL            AUTOMATED
centos                             The official build of CentOS.                   5884                [OK]             
ansible/centos7-ansible            Ansible on Centos7                              128                                     [OK]
jdeathe/centos-ssh                 OpenSSH / Supervisor / EPEL/IUS/SCL Repos - …   114                                     [OK]
consol/centos-xfce-vnc             Centos container with "headless" VNC session…   111                                     [OK]
centos/mysql-57-centos7            MySQL 5.7 SQL database server                   71                                   
imagine10255/centos6-lnmp-php56    centos6-lnmp-php56                              58                                      [OK]
tutum/centos                       Simple CentOS docker image with SSH access      45                                   
centos/postgresql-96-centos7       PostgreSQL is an advanced Object-Relational …   43                                  
kinogmt/centos-ssh                 CentOS with SSH                                 29                                      [OK]
pivotaldata/centos-gpdb-dev        CentOS image for GPDB development. Tag names…   11                                  
guyton/centos6                     From official centos6 container with full up…   10                                      [OK]
nathonfowlie/centos-jre            Latest CentOS image with the JRE pre-install…   8                                       [OK]
drecom/centos-ruby                 centos ruby                                     6                                       [OK]
centos/tools                       Docker image that has systems administration…   6                                       [OK]
pivotaldata/centos                 Base centos, freshened up a little with a Do…   4                                   
darksheer/centos                   Base Centos Image -- Updated hourly             3                                       [OK]
mamohr/centos-java                 Oracle Java 8 Docker image based on Centos 7    3                                       [OK]
pivotaldata/centos-mingw           Using the mingw toolchain to cross-compile t…   3                                   
pivotaldata/centos-gcc-toolchain   CentOS with a toolchain, but unaffiliated wi…   3                                   
miko2u/centos6                     CentOS6 日本語環境                                   2                                       [OK]
indigo/centos-maven                Vanilla CentOS 7 with Oracle Java Developmen…   1                                       [OK]
blacklabelops/centos               CentOS Base Image! Built and Updates Daily!     1                                       [OK]
pivotaldata/centos6.8-dev          CentosOS 6.8 image for GPDB development         0                                    
pivotaldata/centos7-dev            CentosOS 7 image for GPDB development           0                                    
smartentry/centos                  centos with smartentry                          0                                       [OK]

コンテナをダウンロードするには「docker pull OS名:バージョン」とする(:バージョンは省略可能)。今回は「docker pull centos:7」を実行する。

C:\Users\XXXXX>docker pull centos:7
7: Pulling from library/centos
ab5ef0e58194: Pull complete
Digest: sha256:4a701376d03f6b39b8c2a8f4a8e499441b0d567f9ab9d58e4991de4472fb813c
Status: Downloaded newer image for centos:7
docker.io/library/centos:7

docker images」でイメージを確認する。

C:\Users\XXXXX >docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              6678c7c2e56c        11 days ago         127MB
centos              7                   5e35e350aded        4 months ago        203MB

Dockerコンテナの一覧確認

Dockerコンテナの一覧確認は下記コマンド。

  • 起動中のコンテナのみを表示する:docker ps
  • 停止中のコンテナも表示する:docker ps -a

docker fileを作成する。
https://kitsune.blog/dockerfile-summary

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

パワーワードが作れる?ランダム単語合成アプリを作ってみた

はじめに

クリックするだけ!ランダムに2つの単語を「反応」させて、パワーワードを作りましょう!

rand.gif

モードは

  • 形容詞+名詞
  • 副詞+動詞
  • 名詞+助詞+動詞

の3種類です!

phrases.gif

ソースコード

GitHub - Syuparn/LiteralReaction: ランダムに単語を「反応」させて、パワーワードを作ろう

(DockerやVue.jsをはじめて使ったので、汚いところもあると思います…ツッコミ、修正歓迎です)

Webアプリの形で作りましたが、web上では公開していません。
(単語が本当にランダムなので、暴言や不謹慎な表現も生成されるかもしれないからです…)

試したい方は上記リンクからダウンロードしてください。docker-composeを使用しているので、

$ docker-compose -f docker-compose.prod.yml up -d

でコンテナを起動すればlocalhost:8080からアクセスできます。

webアプリケーションの構成

WebサーバとAPIサーバの2段構成になっています。

network.png

WebサーバはUI(html)、APIサーバは単語情報(JSON)をやりとりします。

コンテナもWebサーバとAPIサーバの2つに分けています。
(UIと単語生成を疎結合にして修正しやすくするためです)

containers.png

docker-compose.prod.yml
version: '3'
services:
  apiserver:
    build:
      context: ./apiserver/
      dockerfile: Dockerfile
    ports:
      - "127.0.0.1:5050:5050" # host:container
    expose:
      - "5050" # port for other containers (not host)
  vue-frontend:
    build:
      dockerfile: Dockerfile
      context: ./vue-frontend
    ports:
      - "127.0.0.1:8080:80" # host:container

ただし、ユーザーから見ても別々のURLになってしまうと不格好なので、Webサーバの/api/ではじまるURLにリクエストされた場合はAPIサーバに転送するようにしています。

vue-frontend/nginx_config/default.conf
server {
    listen 80;
    server_name localhost;
    server_tokens off;

    location / {
        # デフォルトではhtmlを返す
        root /usr/share/nginx/html;
        try_files $uri $uri/ @dynamic;
    }

    location /api/ {
        # URLが"/api/"ではじまる場合のみ、APIサーバに転送
        # URLのうち"/api/"に続く部分のみを取り出す
        rewrite /api/(.*) /$1 break;
        # docker-composeの機能によって、exposeされた他コンテナのポートはアプリケーション名でアクセス可能
        proxy_pass http://apiserver:5050;
        # redirectを無効化(既にrewriteでリダイレクトを設定しているため)
        proxy_redirect off;
        proxy_set_header Host $host;
    }
}

単語情報GETの流れは以下の通りです。(例は「形容詞+名詞」の場合)

  1. クライアントは、単語生成(「反応」)ページを開いたときに、形容詞をlocalhost:8080/api/rand/adjectiveへGETリクエスト
  2. WebサーバがリクエストをAPIサーバhttp://apiserver:5050/rand/adjectiveへ転送
  3. APIサーバがリクエストに基づきランダムな形容詞1つをJSON形式で(Webサーバに)返す
  4. Webサーバはレスポンスをクライアントへ転送
  5. クライアントに形容詞データのJSONが届く
  6. 名詞についても同様

単語データ生成

「MeCab IPADIC」を使用しました。

MeCabは、文章を単語(正確には形態素、ことばの最小単位)ごとに分かち書きするソフトウェアです。

そして、MeCabが参照する形態素の辞書の1つがIPADICです。

品詞ごとにcsvファイルで書かれていて、各行に各形態素の表記、読み、品詞、活用などが格納されています。

Adj.csv
あらっぽい,19,19,6956,形容詞,自立,*,*,形容詞・アウオ段,基本形,あらっぽい,アラッポイ,アラッポイ
あらっぽし,23,23,6956,形容詞,自立,*,*,形容詞・アウオ段,文語基本形,あらっぽい,アラッポシ,アラッポシ
あらっぽから,27,27,6956,形容詞,自立,*,*,形容詞・アウオ段,未然ヌ接続,あらっぽい,アラッポカラ,アラッポカラ
...

このアプリの単語合成モードは

  • 形容詞(終止形)+名詞
  • 副詞+動詞(終止形)
  • 名詞+(助詞)+動詞(終止形)

の3種類です。
この形式で最大限単語を利用するため、(文法的用語には少し不正確ですが)以下のルールで単語を抽出しました。

apiserver/db/format-ipadic-csv.bash
# 形容詞として利用

# 形容詞終止形
cat $PATH_FROM/Adj.csv       | awk -F"," '$10~/^基本形$/ {print $1}' >  $PATH_TO/adj.txt
# (「な」を付けると形容詞になる名詞)+「な」
cat $PATH_FROM/Noun.adjv.csv | awk -F"," '{print $1 "な"}'         >> $PATH_TO/adj.txt
# (「ない」を付けると形容詞になる名詞)+「ない」
cat $PATH_FROM/Noun.nai.csv  | awk -F"," '{print $1 "ない"}'       >> $PATH_TO/adj.txt

# 名詞として利用
# 「ナンセンスさ」を出したいので人名、地名、専門用語は除外し、一般名詞だけ使用

# 名詞
cat $PATH_FROM/Noun.csv          | awk -F"," '{print $1}' >  $PATH_TO/noun.txt
# 「する」を付けると動詞になる名詞
cat $PATH_FROM/Noun.verbal.csv   | awk -F"," '{print $1}' >> $PATH_TO/noun.txt
# 「な」を付けると形容詞になる名詞
cat $PATH_FROM/Noun.adverbal.csv | awk -F"," '{print $1}' >> $PATH_TO/noun.txt
# 「ない」を付けると形容詞になる名詞は単体で使うと不自然なので未使用)

# 副詞として使用

# 副詞
cat $PATH_FROM/Adverb.csv        | awk -F"," '{print $1}'                    >  $PATH_TO/adverb.txt
# 副詞としても使える名詞(「毎日」等)
cat $PATH_FROM/Noun.adverbal.csv | awk -F"," '{print $1}'                    >> $PATH_TO/adverb.txt
## 形容詞連用形(小さい「っ」で終わるものは動詞が後続できないので削除)
cat $PATH_FROM/Adj.csv           | awk -F"," '$10~/^連用テ接続$/ {print $1}' \
                                 | awk       '!/っ$/'                        >> $PATH_TO/adverb.txt

# 動詞として利用

# 動詞
cat $PATH_FROM/Verb.csv        | awk -F"," '$10~/^基本形$/ {print $1}'        >  $PATH_TO/verb.txt
# (「する」を付けると動詞になる名詞)+「する」
cat $PATH_FROM/Noun.verbal.csv | awk -F"," '{print $1 "する"}'                >> $PATH_TO/verb.txt

上記で生成したcsvをSQLiteに流し込んだものを、単語データベースとして使用しました。

apiserver/db/csv2sqlite.bash
sqlite3 $SQL_PATH/$SQL_NAME << EOS

/* create tables */
.read ./db/init.sql

/* let col separator "," */
.separator ','

/* import word data csvs */
.mode csv
.import $CSV_PATH/adj.csv adjectives
.import $CSV_PATH/adverb.csv adverbs
.import $CSV_PATH/noun.csv nouns
.import $CSV_PATH/verb.csv verbs
EOS
apiserver/db/init.sql
drop table if exists adjectives;
create table adjectives (
    id integer primary key,
    word text
);

drop table if exists adverbs;
create table adverbs (
    id integer primary key,
    word text
);

drop table if exists nouns;
create table nouns (
    id integer primary key,
    word text
);

drop table if exists verbs;
create table verbs (
    id integer primary key,
    word text
);

(個人的)面白かった生成結果

Screenshot from 2020-03-14 23-17-22.png
私たちがコードを書けるのは、数学様のおかげでございます。

Screenshot from 2020-03-14 22-43-34.png
ウケ狙いちゃうわ!

Screenshot from 2020-03-14 22-08-33.png
こんなアプリ作っちゃうくらいだからしょうがないね

Screenshot from 2020-03-14 22-42-12.png
文章が成立している!

意外とフレーズが成立する割合が高く(体感100回に1回くらい?)、他にも以下のような「まともな」フレーズが生成されました。

居場所を失う
酷い蛇行
自我を失う
泥棒を訴える
移り気なロマンチスト
やさしいインターフェース

はまったところ

docker-compose buildできない

docker-composeapt installでインストールすると古いバージョンが入ってしまいます…

そして、古いバージョンのdocker-composeでバージョン3のdocker-compose.ymlを使うとビルドに失敗します。

apt installではなくcurlで最新バージョンをダウンロードしましょう

Install Docker Compose | Docker Documentation

(公式ドキュメントはちゃんと読まねば…反省)

go buildできない

Go1.13からはライブラリ管理の方法が変わったため、最初にgo mod initをする必要があります。

このコマンドを打つと、モジュールの依存関係ファイルgo.modやモジュールが本物か確かめるためのチェックサムgo.sumが生成されます。

Go Modules - Qiita

Go 1.13 に向けて知っておきたい Go Modules とそれを取り巻くエコシステム - blog.syfm

その代わり、go.modのおかげでライブラリを手動でgo getする必要がなくなりました!
go build時に自動でダウンロードされる)

コンテナ作成中に生成した実行ファイルが消える

volumesCOPYを混同していました。

Dockerfile中でCOPYすると、コンテナのビルド時にホストのディレクトリをコピーします。

docker-compose.yml中でvolumesを指定すると、コンテナの起動時にコンテナのディレクトリにホストのディレクトリをマウントします。

そのため、ホストのソースをCOPYしてせっかく実行ファイルをビルドしても、同じディレクトリをvolumesに指定するとホストのディレクトリ(もちろん実行ファイルは無い)に隠されてしまいます…

docker-composeのvolumesで指定したホストのディレクトリがマウントされずハマった

conic-gradientが使えない

単語生成画面の集中線はCSSのconic-gradient関数を使用する予定でした

…が、この関数はFirefoxでは非対応です。

conic-gradient() - CSS: カスケーディングスタイルシート | MDN

そこで、同名のnpmパッケージを使ってjs側で模様を生成しました。

conic-gradient - npm

しかし、このパッケージはES5で書かれているのでVue CLI内部でimportできません。

結局、

  1. index.htmlで直接グローバルに読み込む
  2. Vue側ではwindow.ConicGradientの形で呼び出す
  3. npm run buildではビルドされないので、別途モジュールをstaticにコピーする

という手順を取りました。

vue-frontend/index.html
<!DOCTYPE html>
<html>
...
  <body>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    <!-- ここでモジュールを読み込む(prefixfreeはconic-gradientの依存モジュール) -->
    <script src="./static/prefixfree.min.js"></script>
    <script src="./static/conic-gradient.js"></script>
  </body>
</html>
vue-frontend/src/components/bangBackground.vue
<script>
export default {
  name: 'bangBackground',
  data: function () {
    return {
      bangSVG: new window.ConicGradient({
        repeating: true,
        stops: `#ffffff 0,
                #ffffff 2.0%,
                #AAAAAA 2.125%,
                #AAAAAA 2.375%,
                #ffffff 2.5%`
      })
    }
  }
}
</script>
vue-frontend/Dockerfile
FROM node:lts-alpine as builder

RUN mkdir -p /app
WORKDIR /app

RUN npm install -g http-server

COPY ./package*.json ./
RUN npm install \
    # conic-gradientモジュールをstaticにコピー
    && mkdir -p static/ \
    && cp node_modules/conic-gradient/conic-gradient.js static/ \
    && cp node_modules/prefixfree/prefixfree.min.js static/

COPY . .
RUN npm run build

FROM nginx:stable-alpine as product

COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx_config/default.conf /etc/nginx/conf.d/default.conf

CMD ["nginx", "-g", "daemon off;"]

参考文献

Go言語

APIサーバ
golangでREST APIをやってみた① - Qiita

SQLiteとの接続
golangでSQLite3を使ってデータベースを操作する方法まとめ | Black Everyday Company

MeCab

IPADICダウンロード方法
Alpine LinuxでMeCab with NEologd - Qiita

Vue.js

SPA(シングルページアプリケーション)のつくり方
【Vue.js】爆速でSPAを作る - Qiita

axiosを使ったJSONのGET/POST
Vue-CLIのプロジェクトでaxiosを使ってAPIや外部リソースからのデータを取得する | 大阪市天王寺区SOHOホームページ制作 | デザインサプライ-DesignSupply.-

コンポーネント内部に要素を入れる(公式)
スロット — Vue.js

nginx

URLの一部分だけ取り出してポートフォワーディング(/api/hoge -> apiserver:5050/hoge)
Nginx reverse proxy + URL rewrite - Server Fault

Docker,docker-compose

docker-compose基本操作
docker-compose コマンドまとめ - Qiita

複数サーバ(複数コンテナ)を協調させる方法
マイクロサービスほどじゃないけどウェブサービスを分割開発したい人向けDocker設定を集めるスレ - Qiita

vue-cliビルド方法(公式)
Vue.js アプリケーションを Docker 化する — Vue.js

Golangマルチステージビルド方法

(マルチステージビルドのメリット)
Dockerのマルチステージビルドを使う - Qiita
(Go1.7の記事ですが、Go1.13以上の場合Dockerfileでgo getをする必要はありません)

(go-sqlite3ライブラリを使う場合)
go-sqlite3 が入った状態での Docker のマルチステージビルドを行う - Pistatium note

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

おうちk8sクラスタを作る: Dockerレジストリ編

DSC_1728.JPG
DSC_1727.JPG
写真: 2020年3月7日時点のおうちk8sクラスタ

1. 概要

 本記事は、学習用に構築しているRaspberry Piによるk8sクラスタ、いわゆる「おうちk8sクラスタ」の製作記の「Dockerレジストリ編」です。

 k8sクラスタでDockerコンテナを起動する場合、ノードにDockerイメージを配布するために、Dockerイメージを格納した「Dockerレジストリ」が必要です。(話を簡単にするために、Docker前提で話を進めます)
今回は、Docker Inc.が提供しているDockerイメージ「registry」を使い、k8sのマスターノードにDockerレジストリを構築しました。

 なお、今回のk8sクラスタは限定された環境下でのみアクセスされるため、Dockerレジストリの認証は行っていません。
認証が必要な場合はHarborPortusなどのソフトウェアを使ってDockerレジストリを構築するのが良いかと思います。

2. 環境

 今回の環境は以下の通りです。詳しい環境、構築方法については別記事『Raspberry Pi 4に64ビット版UbuntuでKubernetes環境を構築する』をご参照ください。

  • ハードウェア: Raspberry Pi 4 4GB 4台
  • OS: Ubuntu Server 19.10 ARM64(AArch64)版
  • ノード構成:
    • マスターノード: 1台
    • ワーカーノード: 3台
ubuntu@k8s-m1:~$ cat /etc/os-release
NAME="Ubuntu"
VERSION="19.10 (Eoan Ermine)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 19.10"
VERSION_ID="19.10"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=eoan
UBUNTU_CODENAME=eoan

ubuntu@k8s-m1:~$ uname -a
Linux ubuntu 5.3.0-1014-raspi2 #16-Ubuntu SMP Tue Nov 26 11:18:23 UTC 2019 aarch64 aarch64 aarch64 GNU/Linux

ubuntu@k8s-m1:~$ cat /proc/cpuinfo
...
Hardware    : BCM2835
Revision    : c03112
Serial      : 10000000794dd63d
Model       : Raspberry Pi 4 Model B Rev 1.2

ubuntu@k8s-m1:~$ cat /proc/meminfo
MemTotal:        3882408 kB
MemFree:         1965400 kB
MemAvailable:    3563220 kB
...

ubuntu@k8s-m1:~$ kubectl get nodes --output wide
NAME     STATUS   ROLES    AGE     VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE       KERNEL-VERSION      CONTAINER-RUNTIME
k8s-m1   Ready    master   26m     v1.17.3   192.168.1.211   <none>        Ubuntu 19.10   5.3.0-1017-raspi2   docker://19.3.6
k8s-n1   Ready    <none>   17m     v1.17.3   192.168.1.212   <none>        Ubuntu 19.10   5.3.0-1017-raspi2   docker://19.3.6
k8s-n2   Ready    <none>   2m44s   v1.17.3   192.168.1.213   <none>        Ubuntu 19.10   5.3.0-1017-raspi2   docker://19.3.6
k8s-n3   Ready    <none>   2m39s   v1.17.3   192.168.1.214   <none>        Ubuntu 19.10   5.3.0-1017-raspi2   docker://19.3.6

ubuntu@k8s-m1:~$ kubectl get pods --all-namespaces --output wide
NAMESPACE     NAME                             READY   STATUS    RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
kube-system   coredns-6955765f44-jz5pv         1/1     Running   0          26m     10.244.0.3      k8s-m1   <none>           <none>
kube-system   coredns-6955765f44-whxsx         1/1     Running   0          26m     10.244.0.2      k8s-m1   <none>           <none>
kube-system   etcd-k8s-m1                      1/1     Running   0          26m     192.168.1.211   k8s-m1   <none>           <none>
kube-system   kube-apiserver-k8s-m1            1/1     Running   0          26m     192.168.1.211   k8s-m1   <none>           <none>
kube-system   kube-controller-manager-k8s-m1   1/1     Running   0          26m     192.168.1.211   k8s-m1   <none>           <none>
kube-system   kube-flannel-ds-arm64-58rgk      1/1     Running   0          21m     192.168.1.211   k8s-m1   <none>           <none>
kube-system   kube-flannel-ds-arm64-7gcj5      1/1     Running   0          17m     192.168.1.212   k8s-n1   <none>           <none>
kube-system   kube-flannel-ds-arm64-b4lc9      1/1     Running   0          3m4s    192.168.1.213   k8s-n2   <none>           <none>
kube-system   kube-flannel-ds-arm64-skgjw      1/1     Running   0          2m59s   192.168.1.214   k8s-n3   <none>           <none>
kube-system   kube-proxy-bh8c5                 1/1     Running   0          2m59s   192.168.1.214   k8s-n3   <none>           <none>
kube-system   kube-proxy-shjkv                 1/1     Running   0          17m     192.168.1.212   k8s-n1   <none>           <none>
kube-system   kube-proxy-tngmj                 1/1     Running   0          26m     192.168.1.211   k8s-m1   <none>           <none>
kube-system   kube-proxy-ttx28                 1/1     Running   0          3m4s    192.168.1.213   k8s-n2   <none>           <none>
kube-system   kube-scheduler-k8s-m1            1/1     Running   0          26m     192.168.1.211   k8s-m1   <none>           <none>

3. 構築

 今回利用するregistryは単一のDockerイメージで構成されており、とても簡単にデプロイすることができます。今回は以下の設定でデプロイしました。

  • Dockerレジストリはマスターノードk8s-m1に配置する。
  • 永続化が必要なファイルは、マスターノードのストレージに格納する。
  • Dockerイメージはregistry:2.7を使用する。
  • ホストネットワークを利用し、5000/tcpで待ち受けする。

使用した定義ファイルは以下の通りです。

docker-registry.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: docker-registry
  labels:
    app: docker-registry
spec:
  replicas: 1
  selector:
    matchLabels:
      app: docker-registry
  template:
    metadata:
      labels:
        app: docker-registry
    spec:
      hostNetwork: true
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      nodeSelector:
        kubernetes.io/hostname: k8s-m1
      containers:
      - name: docker-registry
        image: registry:2.7
        ports:
        - containerPort: 5000
        volumeMounts:
        - name: registry
          mountPath: /var/lib/registry
      volumes:
      - name: registry
        hostPath:
          type: Directory
          path: /var/lib/registry

 定義ファイルの適用、curlによる簡易的な動作確認の手順は以下の通りです。

ubuntu@k8s-m1:~$ kubectl apply -f docker-registry.yaml
ubuntu@k8s-m1:~$ kubectl get pods -o wide
NAME                              READY   STATUS    RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
docker-registry-5c5cb844f-h7mzb   1/1     Running   0          4m34s   192.168.1.211   k8s-m1   <none>           <none>
nginx-munin-7kvf8                 1/1     Running   12         23d     10.244.3.14     k8s-n3   <none>           <none>
nginx-munin-8f88x                 1/1     Running   7          23d     10.244.1.9      k8s-n1   <none>           <none>
nginx-munin-jw4jd                 1/1     Running   5          23d     10.244.0.18     k8s-m1   <none>           <none>
nginx-munin-m8flt                 1/1     Running   5          23d     10.244.2.8      k8s-n2   <none>           <none>

ubuntu@k8s-m1:~$ curl -v http://localhost:5000/
*   Trying 127.0.0.1:5000...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 5000 (#0)
> GET / HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.65.3
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Cache-Control: no-cache
< Date: Mon, 09 Mar 2020 07:45:47 GMT
< Content-Length: 0
<
* Connection #0 to host localhost left intact

4. 動作確認

 Dockerデーモンは、デフォルトではTLS接続(暗号化あり)のDockerレジストリのみ使用できます。
今回構築したDockerレジストリは非TLS接続(暗号化なし)を用いるため、Dockerデーモンの設定を変更する必要があります。
具体的には、設定ファイル/etc/docker/daemon.jsoninsecure-registriesキーにホスト名、ポート番号を記載する必要があります。
設定ファイルを変更し、Dockerデーモンの再読み込み(再起動は不要)を行うことで、非TLS接続のDockerレジストリに接続できるようになります。なお、この設定はすべてのノードで行う必要があります。

ubuntu@k8s-m1:~$ sudo vim /etc/docker/daemon.json
ubuntu@k8s-m1:~$ cat /etc/docker/daemon.json
{
  "insecure-registries": ["k8s-m1.local:5000"]
}

ubuntu@k8s-m1:~$ sudo systemctl reload docker

 動作確認の第1ステップとして、マスターノード(k8s-m1)にてDocker Hubからhello-worldイメージを取得(docker pull)し、構築したDockerレジストリに転送(docker push)してみました。
マスターノードの/var/lib/registry以下に、転送されたDockerイメージが格納されているのが確認できます。

ubuntu@k8s-m1:~$ docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
256ab8fe8778: Pull complete
Digest: sha256:fc6a51919cfeb2e6763f62b6d9e8815acbf7cd2e476ea353743570610737b752
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest

ubuntu@k8s-m1:~$ docker tag hello-world k8s-m1.local:5000/hello-world
ubuntu@k8s-m1:~$ docker push k8s-m1.local:5000/hello-world
The push refers to repository [k8s-m1.local:5000/hello-world]
167d9097a0a0: Pushed
latest: digest: sha256:963612c5503f3f1674f315c67089dee577d8cc6afc18565e0b4183ae355fb343 size: 525

ubuntu@k8s-m1:~$ ls -l /var/lib/registry/
total 4
drwxr-xr-x 3 root root 4096 Mar  9 16:53 docker

 続いて、ワーカーノードの1つ(k8s-n1)で、構築したDockerレジストリからDockerイメージを取得してみました。

ubuntu@k8s-n1:~$ sudo vim /etc/docker/daemon.json
ubuntu@k8s-n1:~$ sudo systemctl reload docker
ubuntu@k8s-n1:~$ docker pull k8s-m1.local:5000/hello-world
Using default tag: latest
latest: Pulling from hello-world
256ab8fe8778: Pull complete
Digest: sha256:963612c5503f3f1674f315c67089dee577d8cc6afc18565e0b4183ae355fb343
Status: Downloaded newer image for k8s-m1.local:5000/hello-world:latest
k8s-m1.local:5000/hello-world:latest

 docker pushdocker pullともに正常に動作することが確認できました。なお、認証は行っていないのでdocker loginは不要です。

 以上、Dockerレジストリ編でした。
また余裕があれば、他の記事(電源編、ファン編、ケース編)なども書きたいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RaspberryPi4(Raspbian 10 buster)にdockerインストールでハマったのでメモ

背景

RaspberryPi4にflask(Python用Webフレームワーク)を構築するためdockerを入れようとしたところハマったのでメモ。

結論

  1. systemdの設定ファイルを変更する
  2. iptables-nfsをやめてiptables-legacy(従来のiptables)を使用する

まとめたコマンド↓

$ sudo apt install docker.io
$ sudo sed --in-place=~ 's/fd:\/\//unix:\/\/\/var\/run\/docker.sock/' /lib/systemd/system/docker.service
$ sudo update-alternatives --set iphtables /usr/sbin/iptables-legacy
$ sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

過程

aptでインストールするも進捗33%でコケる。

$ sudo apt install docker.io

いろいろ環境をいじって(どのようにかは忘れた)もNG。

$ sudo apt install docker.io
...
Running kernel seems to be up-to-date.

Failed to check for processor microcode upgrades.

No services need to be restarted.

No containers need to be restarted.

No user sessions are running outdated binaries.

デーモンを手動で起動して怒られたのでログを見る

$ sudo systemctl restart docker
Job for docker.service failed because the control process exited with error code.
See "systemctl status docker.service" and "journalctl -xe" for details.
$ journalctl -xe
...

-- The job identifier is 1439.
 3月 16 14:15:18 raspberrypi systemd[1]: docker.service: Start request repeated too quickly.
 3月 16 14:15:18 raspberrypi systemd[1]: docker.service: Failed with result 'exit-code'.
-- Subject: Unit failed
-- Defined-By: systemd
-- Support: https://www.debian.org/support
--
-- The unit docker.service has entered the 'failed' state with result 'exit-code'.
 3月 16 14:15:18 raspberrypi systemd[1]: Failed to start Docker Application Container Engine.
-- Subject: A start job for unit docker.service has failed

...

よく分かんないのでsystemdの設定ファイルを確認しつつこんな記事を発見。
14行目をコメントアウト、15行目を追加して設定のリロード。(まだデーモンは起動しない)
参考記事1

$ vim /lib/systemd/system/docker.service
...
  8 [Service]
  9 Type=notify
 10 # the default is not to use systemd for cgroups because the delegate issues still
 11 # exists and systemd currently does not support the cgroup feature set required
 12 # for containers run by docker
 13 EnvironmentFile=-/etc/default/docker
 14 #ExecStart=/usr/sbin/dockerd -H fd:// $DOCKER_OPTS
 15 ExecStart=/usr/sbin/dockerd -H unix:///var/run/docker.sock $DOCKER_OPTS
...
$ sudo systemctl daemon-reload

手動で確認。めっちゃ進んだが、まだエラー。
iptablesでエラーが出てるっぽいので、手動でiptablesのみを起動。
ん?なんか動かん。iptables変わってる?
参考記事2
このお方が絡んでるのであんまり昔のiptablesに変えたくないけど。。。
変えたくない理由

$ sudo /usr/sbin/dockerd -H unix:///var/run/docker.sock
...
INFO[2020-03-16T14:50:38.947663447+09:00] Loading containers: start.
INFO[2020-03-16T14:50:39.335799251+09:00] stopping event stream following graceful shutdown  error="<nil>" module=libcontainerd namespace=moby
INFO[2020-03-16T14:50:39.336934234+09:00] stopping healthcheck following graceful shutdown  module=libcontainerd
INFO[2020-03-16T14:50:39.337271358+09:00] stopping event stream following graceful shutdown  error="context canceled" module=libcontainerd namespace=plugins.moby
INFO[2020-03-16T14:50:39.337955589+09:00] pickfirstBalancer: HandleSubConnStateChange: 0x492c070, TRANSIENT_FAILURE  module=grpc
INFO[2020-03-16T14:50:39.338036439+09:00] pickfirstBalancer: HandleSubConnStateChange: 0x492c070, CONNECTING  module=grpc
Error starting daemon: Error initializing network controller: error obtaining controller instance: failed to create NAT chain DOCKER: iptables failed: iptables -t nat -N DOCKER: iptables: Operation not supported.
 (exit status 1)
$ sudo iptables -t nat -N DOCKER
iptables: Operation not supported.
$ sudo iptables --list
iptables: Operation not supported.

$ sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
$ sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy

やっと動いた。

$ sudo systemctl restart docker
$ sudo docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker + VSCodeでGoの環境構築(ホットリロード対応)

はじめに

個人開発で最近Go言語を使う機会が増えてきました。
Go言語で開発するにあたり私が感じたことは、

  • Dockerで動かしたい
  • ホットリロード機能が欲しい
  • 開発用・本番用でコンテナを分けたい
  • 開発時は、VSCode上でコンテナ内とリモート接続して作業したい

色々な方々のDocker環境を参考にDockerでGo環境を作りました。
よろしければ参考にしてください。

ホスト環境

  • Docker: ver.19.03.8
  • docker-compose: ver.1.25.4
  • VSCode: ver.1.43.0

ホットリロード

Go言語でホットリロードをする際、調べていたら、

  • fresh
  • realize

があるのを知りました。
しかし、筆者はrealize の方はエラー(error: returned a non-zero code: 1)が発生してgo get ができませんでした。

一度コンテナを立ち上げて、コンテナ内でgo get したらうまく行くのですが解決出来ませんでした...

ですので今回はfresh を使用します。

手順

  1. Dockerfile(開発用&本番用) + docker-compose.yml の作成
  2. Remote Containers の設定
  3. ホットリロードの設定
  4. 開発環境の起動
  5. 開発環境の動作確認
  6. 本番環境の起動

開発環境

はじめに作業ディレクトリを作ります。

/
# 作業ディレクトリ作成
$ mkdir go-work
# 作業ディレクトリへ移動
$ cd go-work

1. Dockerfile(開発用&本番用) + docker-compose.yml の作成

続いてDockerfiledocker-compose.yml を書いていきます。
下記コマンドからファイルを作成してください。

/go-work
$ touch docker-compose.yml
$ mkdir -p docker/golang
$ touch docker/golang/Dockerfile.dev
$ touch docker/golang/Dockerfile.dep

※ Dockerfileの言語サポート

Dockerfile.dev(.dep) はVSCodeの標準では言語サポートされていないので設定を追加します。
設定されている方は次へ飛ばしてください。

  1. [Code] -> [基本設定] -> [設定]
  2. Files: Associations で検索
  3. settings.json で編集
settings.json
{
  "files.associations": { 
    "Dockerfile.dev": "dockerfile",
    "Dockerfile.dep": "dockerfile"
  }
}

Docker + docker-composeの設定

  • 開発用Dockerfile
/go-work/docker/golang/Dockerfile.dev
FROM golang:1.14.0-alpine3.11

SHELL ["/bin/ash", "-c"]
WORKDIR /go/src/app
COPY ./app ./
EXPOSE 8080
ENV GO111MODULE=on

RUN apk add --no-cache alpine-sdk

# Golang ホットリロード(freshのインストール)
RUN go get github.com/pilu/fresh

# Golang 環境構築(任意)
RUN go get github.com/go-delve/delve/cmd/dlv \
    github.com/rogpeppe/godef \ 
    golang.org/x/tools/cmd/goimports \
    golang.org/x/tools/cmd/gorename \
    sourcegraph.com/sqs/goreturns \
    github.com/ramya-rao-a/go-outline \
    golang.org/x/tools/gopls@latest
  • 本番用Dockerfile
/go-work/docker/golang/Dockerfile.dep
FROM golang:1.14.0-alpine3.11 as builder

WORKDIR /go/src/app
COPY ./app ./
ENV GO111MODULE=on 
RUN go mod download
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /go/bin/app

FROM alpine:latest

RUN apk --no-cache add ca-certificates
COPY --from=builder /go/bin/app /go/bin/app
ENTRYPOINT [ "/go/bin/app" ]
EXPOSE 8080
  • docker-compose
/go-work/docker-compose.yml
version: '3.7'

services:
  app:
    container_name: go-app
    build:
      context: .
      # Remote Containerが立ち上がるまで待機
      dockerfile: docker/golang/Dockerfile.dev
    ports:
      - 8080:8080
    volumes:
      - ./app:/go/src/app:cached
    command: /bin/ash -c "while sleep 1000; do :; done"

2. Remote Containers の設定

インストール

インストールしていない方は、 Remote-Containers からインストールしてください。

準備

まずはじめにVSCode の左下のアイコンをクリックしてください。
01-icon.png
すると、コマンドパレッドが開きますので、
Remote-Containers: Add Development Container Configuration Files...
と検索して選択してください。

02-remote-containers.png

選択したら、
From 'docker-compose.yml'
を選択してください。

03-remote-containers.png

選択後.devcontainer ディレクトリが作成され、設定ファイルが格納されています。

設定

.devcontainer
    ├── devcontainer.json
    └── docker-compose.yml

まずはじめに、docker-compose.yml はもう作成してあるので、
.devcontainer 内のdocker-compose.yml は削除してください。

下記のコマンドを実行してファイルを削除してください。

/go-work
$ rm .devcontainer/docker-compose.yml

次にdevcontainer.json を編集します。

/go-work/.devcontainer/devcontainer.json
{
  "name": "go",
  "dockerComposeFile": [
    "../docker-compose.yml"
  ],
  "service": "app",
  "workspaceFolder": "/go/src/app",
  "settings": { 
    "terminal.integrated.shell.linux": "/bin/ash",
    "go.gopath": "/go"
  },
  "extensions": [
    "ms-vscode.go",
  ],
  "shutdownAction": "stopCompose"
}

3. ホットリロードの設定

準備

まずはGoアプリを開発する作業ディレクトリを作成します。
その後ホットリロードを行うためのfresh の設定ファイルを作成します。

ちなみに設定ファイルを作成しなくても大丈夫ですのでこちらは任意で!

下記のコマンドを実行してください。

/go-work
$ mkdir app
$ cd app
# /go-work/app
$ touch .fresh.conf

設定

/go-work/app/.fresh.conf
root:              .
tmp_path:          ./tmp
build_name:        runner-build
build_log:         runner-build-errors.log
valid_ext:         .go, .tpl, .tmpl, .html
no_rebuild_ext:    .tpl, .tmpl, .html
ignored:           assets, tmp
build_delay:       600
colors:            1
log_color_main:    cyan
log_color_build:   yellow
log_color_runner:  green
log_color_watcher: magenta
log_color_app:

上記の設定はテンプレートから持ってきています。
細かい設定は任意で!

4. 開発環境の起動

さて、いよいよコンテナを起動します。
VSCode から左下のアイコンをクリックしてください。

01-icon.png

すると、コマンドパレッドが開きますので、
Remote-Containers: Reopen in Container
を検索して選択してください。

04-remote-containers.png

すると、画面が切り替わります。
この時点でDockerイメージが作成され、コンテナが自動で起動します。
起動するまでしばらく時間がかかりますので待機...

しばらくするとコンテナとリモートで繋がり作業ディレクトリに移ります。

05-remote-containers.png

VSCode の左下のアイコンも変わっているはずです。
VSCode 上でターミナルを開くと、コンテナ内のターミナルに切り替わっています。

コンテナ内
/go/src/app #

5. 開発環境の動作確認

ここからはコンテナ内で作業していきます。
ホットリロードの動作を確認するためにGo のプログラムを開発していきます。

main.go の作成

開発するためのファイルを作成します。

/go/src/app
touch main.go
go mod init main

つづいてmain.go に簡単なWebサーバを作成します。

/go/src/app/main.go
// ...省略
func init() {
  http.HandleFunc("/", index)
}

func index(w http.ResponseWriter, r *http.Request) {
  fmt.Fprint(w, "Hello World")
}

func main() {
  fmt.Print("Server Start")
  if err := http.ListenAndServe(":8080", nil); err != nil {
    panic(err)
  }
}

実行

main.go を実行するのですが今回はfresh を使って実行します。
VSCode 内のコンテナで実行しても良いのですが、こちらは開発時で利用したいので今回は別ターミナルで実行します。

別ターミナルでコンテナ内に入り、ホットリロードを起動させます。

別ターミナル
$ docker exec -it go-app /bin/ash

# コンテナ内: /go/src/app
fresh -c .fresh.conf

main.go が実行されますので確認作業に移ります。

確認

確認は、ブラウザ または、ターミナル で確認します。

  • ブラウザの場合は、http://localhost:8080 にアクセス
  • ターミナルの場合は、curl http://localhost:8080 を実行

Hello World が返ってくれば起動しています。

変更

つづいてホットリロードが正常に起動しているかを確認したいので、
fresh を起動したままVSCode に戻ってください

VSCode上でmain.go を変更し、保存してください。

/go/src/app/main.go
func index(w http.ResponseWriter, r *http.Request) {
  - fmt.Fprint(w, "Hello World")
  + fmt.Fprint(w, "Hello Golang")
}

保存したら再度、確認作業を行ってください。
Hello Golang が返ってくればホットリロードは正常に起動しています。

6. 本番環境の起動

本番環境はDockerをビルドして実行すれば良いだけです。

イメージのビルド

/go-work
$ docker build -t go-app -f ./docker/golang/Dockerfile.dep .

コンテナの実行

/go-work
$ docker run --name go-app go-app -p 8080:8080 -d . /bin/ash
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerコンテナへローカルファイルのダンプをコピーしてリストアする

私自身の覚えが良くないのもあり、何度も複数コマンドをググって辛みだったため、備忘録として。
まだエンジニアとして8ヶ月ですので、何かミスなどあればマサカリいただければと。

1. ローカルファイルディレクトリへ移動

cd your/local/dump

2. (docker起動中で)dockerのデータベースコンテナのIDを調べる

コンテナIDは 「23fd80dl」のような文字列です。

docker ps

3. ローカルからコンテナへコピーする

docker cp ローカルダンプファイル コンテナ名:/ダンプファイル名

例えばこんな感じ

docker cp qiita.20200316.dump  コンテナ名:/tmp/qiita.20200316.dump

4. 起動中のデータベースコンテナに入る

docker-composeを利用していて、かつ、bashの場合(docker-compose.yml直下で)

docker-compose exec データベースサービス名 bash

5. ダンプファイルをcpしたディレクトリへ移動

3.で /tmpへコピーしたので移動

cd tmp

6. ダンプする

lsしたら、dockerコンテナへコピーしたダンプファイルが直下に見えることを確認してください。

mysql -u ユーザー名 -pパスワード -D データベース名 < ダンプファイル名

以上です〜

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

使ったことがないDockerを使う気にさせる使用事例

はじめに

Dockerを学ぶ場合、会社のプロジェクトで使うから勉強する事になるパターンと
よく使われていることから使ってみたい!という2パターンに分けられると思います(自分は後者でした)

勉強した際いまいちどう使えばいいのかわからず、業務で使って理解した部分が色々あったので
便利だなと思ったユースケースと利点についてまとめました。
読んで使ってみたいと思う人が一人でも増えればいいと思います。

個人開発で使用する

PC内にDockerでlinuxの開発環境を作る(Win or Mac)

メリット
・母艦PCと言語バージョンが違う開発がパッケージ切り替え無しで実施できる

 DockerでLinux環境を作成し、その中に言語パッケージ等を入れて開発環境を構築します。
 本質は「どこから接続しても同条件で開発できる環境をDockerイメージとしてパッケージ化できる」点です。
 イメージさえあれば別PCを購入してもDockerさえ導入すれば同じ環境がすぐ構築でき、
 AWS等のクラウド上でコンテナを立てればSSH接続するだけですぐ開発に取り掛かることができます。
 ※Linuxを含んだDockerコンテナを作る

・実質linux内で開発しているためデプロイする場合のOS差異がなく、コンテナ作成から公開が簡単にできる。

 上とほぼ似ていますが、linux内での開発になるのでそのままdockerfileを記述しイメージを作成、
 ECR、GCR等のコンテナ用クラウドにアップすることですぐに開発したコンテナを公開できます。
 自分の環境で開発した物をEC2等にデプロイする場合と比べて環境差異が生まれる可能性が少なく便利です。

会社のプロジェクトで使用する

開発環境として使用する

コンテナを用いて複数人の環境をすぐに作成できる

 Dockerイメージをpushするインスタンスを変更するだけで複数環境を簡単に作成することができます。
 開発環境の配布も可能なためプロジェクトインが簡単にできたり、テスト用のインスタンス生成等にも
 柔軟に対応が可能です。スタートアップ時にはいろいろなモジュールを変更して試してみることも多いため、
 変更しない部分(メインロジック等)を1個のDockerイメージにして変更がある部分のみを別イメージとして
 docker-composeの記述で環境を試し、必要ないコンテナはすぐ廃棄することで作業効率が向上します。
 (ローカルで同様の事をする場合、パッケージの削除・エラー解消などが必要となり膨大な作業が発生します)

本番運用のために使用する

スケーリングが容易なため、サービスの規模に応じてベストな運用ができる

 ソーシャルゲームなどではイベントがあるとアクセスが多くなったり、夜間のアクセスが減少することから
 スケーリング不可なシステムだとリソースの無駄やアクセス過多によるサーバー落ちの可能性があります。
 Dockerを使用することによりコンテナ単位でのスケールアウト・スケールインが可能なため、
 アクセスに応じた構成をフレキシブルに適応しながら運用することができます。
 

サービス運用の潤滑化・高速化

 開発に関わる作業(テスト・デプロイ・スケーリング等)が楽になることからプロダクトそのものに集中でき、
 技術面だけではなく企画時間~作業時間など全体の時間削減に繋がります。
 ※うまく説明ができるメンバーがいる前提であれば、テストメンバーを増やす際も環境構築が即時可能で
  開発メンバーのスケーリングが容易にできるのはすごくメリットに感じました。

Dockerに関する気になること

別に使わなくても開発はできる・採用企業にジョインする難しさ

 そもそもDockerが使用されるまでの運用法が間違っているわけでもないので、新規に導入する時間を考えると
 案件を1件でも多く受注し、同じ開発を続けることも企業にとっては一つの選択だと思います。
 2019年の記事では国内でDockerコンテナを本番利用している企業は9.2%という話もあり、該当企業に参加し
 その案件に参画するまでもいくつかの壁が存在します。

0からの勉強コストが高い

 経験のあるメンバーがいない場合、7人のメンバーが1日でDockerを学んでも1人週の工数がかかります。
 どんな新しい技術でも調査時間は必要ですが、前述の「使用しなくても開発は進められる」ということもあり
 この時間を「必要」と捉えるか・チームで何人Docke経験があるかで導入のハードルが変化します。

採用事例・知見の問題

 特に運用フェーズでの採用率の低さはナレッジが全然なかったことが大きい気がします。
 最近はAWSのイベントでも有名企業Docker採用事例のプレゼンテーションがあったり、
 企業が開催しているLT記事でも便利だなーと思う事例を見つけたりします。
 後追いで採用する上では参考にできるユースケースも増えており選択肢としては非常に魅力的だと思います。
 便利とは言っても決して銀の弾丸ではないので、他技術と比べ有利かを考えながら採用する必要があります。

まとめ

メリット

環境差異を最小限に抑えることができストレスが少なく開発・運用することができる
・使い方によってあらゆるフェーズで使えるため、トータルの時間が削減できる
・採用企業の面接を受ける時、Docker運用について受け答えができるとウケが良い

デメリット

・ある程度勉強時間が必要なので継続的に使用していくつもりがないならメリットが薄い
・採用チームに参加できるか、あるいは導入を認めてもらえるかは企業次第

参考

個人開発

Dockerで開発環境構築を10倍楽にしたはなし
 VS CodeのRemote Containersを使ってコンテナ内で開発する
VSCode の Remote - Containers 拡張を試してみた

運用・スケーリング関連

【AWS】Auto Scalingする前に知っておくべき7つのこと
 ロマサガRSで大規模負荷を処理する Amazon ECS & Docker運用知見
 スケールアウトの基礎的な考え方
2018年なぜ私達はコンテナ/Dockerを使うのか
Mastodon・Netflixに見る、コンテナの未来 コンテナはサービス開発の主流になり得るか?

※★は参考にした以上に個人的に面白かった記事です

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

1行追加のみ! Net::HTTPで発生するcertificate verify failedを回避

外部APIを叩くのに、Docker使っていたらエラーが発生

SSL_connect returned=1 errno=0 state=error: certificate verify failed (self signed certificate in certificate chain)

原因を調べるのに疲れた。
ローカル環境のみで発生するので真面目に対応するのも面倒。
本番はDocker使ってないし。
楽できる方法、探した。

解決策1

config/initailizersのファイルに以下を追記する。

OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE if Rails.env.development?

参照:Rails5 devise twitterソーシャルログイン ローカル環境でのエラー解消

ただ、これだと、
・サーバー再起動が必要
・ローカル環境のログでalready initialized constant OpenSSL::SSL::VERIFY_PEER的な警告がうざい
というデメリットがある。

もっと楽、したい。
テキトーに生きたい。

解決策2

  def api(url)
    uri = URI.parse(url)
    req = Net::HTTP::Get.new(uri)
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = (uri.scheme == 'https')
    http.verify_mode = OpenSSL::SSL::VERIFY_NONE # これ追加。
    res = http.start { |h| h.request(req) }

    JSON.parse(res.body)
  end

1行追加で動いた。
テキトーにif分岐追加しても1行で済む。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laradockをやる時にコンテナがdocker-composeでもなかなか立ち上がってくれなかった話

Laradockを使っての環境構築にチャレンジしてみました。
Windows10 homeを使っているので、Docker for Desktopは使えず、
かつInsider Previewには切り替えたくないなと思いましたので、
Docker Toolboxをインストール!

https://docs.docker.com/toolbox/toolbox_install_windows/

こちらリンクですが、入ってみても分かる通り、非常にわかりにくいUIですが頑張ってインストールしましょう。
その際に、gitとvirtual boxがインストールしますかと選択肢がでますが、
すでにインストールしている人はダブルと不具合になるのでチェックは外しておきましょう。

インストール完了するとDocker Quickstart Terminalgが使えるのでクリックして起動。
初回はけっこう時間がかかります。
終了したら、おなじみのクジラのAAとIPアドレスが採番されて完了です。

実際にVirtual Boxを開いてみてみると、「default」というボックスが立ち上がっているのが見てわかります。

その後、任意のターミナル(せっかく開いているのでDocker Quickstart Terminalでよいかと)で

$ docker --version

と入力するとバージョンが返ってきたらインストール完了です。

続いて任意のディレクトリ(僕はいつもCフォルダ直下に作っています)で

/c
$ mkdir docker-workspace

と打って作業用フォルダを作りましょう。

/c
$ cd docker-workspace

でそこに移動して、Laradockをインストールします。

docker-workspace
$ git clone https://github.com/Laradock/laradock.git
$ ls
> laradock
$ cd laradock

次にenvファイルの名前を書き換えます。

laradock
$ cp env-example .env

ここまでできたら、いよいよコンテナを立ち上げていきます。

laradock
$ docker-compose up -d nginx mysql phpmyadmin workspace

こちらもプロセスにかなりの時間が初回はかかります。
そして、ほとんどの方は問題なく終了するかと思いますが、
私の場合は、こんなエラーがでてきました。

Starting phpmyadmin ... error

ERROR: for phpmyadmin  Cannot start service phpmyadmin: driver failed programming external coStarting phpmyadmin ... error
006): Bind for 0.0.0.0:8080 failed: port is already allocated

ERROR: for workspaceCannot start service workspace: driver failed programming external connectivity on endpoint workspace(xxxxxxxxx): Bind for 0.0.0.0:8080 failed: port is already allocated

どうやら、ポートが被っている??
一旦、再起動してみたり、コンテナを削除して作り直しても無駄なうえ、
lsofコマンドができず、起動しているファイルをkillすることもできなかったので、
.envファイルを編集することにしました。

.env
### WORKSPACE #############################################

WORKSPACE_COMPOSER_GLOBAL_INSTALL=true
WORKSPACE_COMPOSER_AUTH=false
WORKSPACE_COMPOSER_REPO_PACKAGIST=
WORKSPACE_NVM_NODEJS_ORG_MIRROR=
WORKSPACE_INSTALL_NODE=true
WORKSPACE_NODE_VERSION=node
WORKSPACE_NPM_REGISTRY=
WORKSPACE_INSTALL_YARN=true
WORKSPACE_YARN_VERSION=latest
WORKSPACE_INSTALL_NPM_GULP=true
WORKSPACE_INSTALL_NPM_BOWER=false
WORKSPACE_INSTALL_NPM_VUE_CLI=true
WORKSPACE_INSTALL_NPM_ANGULAR_CLI=false
WORKSPACE_INSTALL_PHPREDIS=true
WORKSPACE_INSTALL_WORKSPACE_SSH=false
WORKSPACE_INSTALL_SUBVERSION=false
WORKSPACE_INSTALL_BZ2=false
WORKSPACE_INSTALL_GMP=false
WORKSPACE_INSTALL_XDEBUG=false
WORKSPACE_INSTALL_PCOV=false
WORKSPACE_INSTALL_PHPDBG=false
WORKSPACE_INSTALL_SSH2=false
WORKSPACE_INSTALL_LDAP=false
WORKSPACE_INSTALL_SOAP=false
WORKSPACE_INSTALL_XSL=false
WORKSPACE_INSTALL_SMB=false
WORKSPACE_INSTALL_IMAP=false
WORKSPACE_INSTALL_MONGO=false
WORKSPACE_INSTALL_AMQP=false
WORKSPACE_INSTALL_CASSANDRA=false
WORKSPACE_INSTALL_GEARMAN=false
WORKSPACE_INSTALL_MSSQL=false
WORKSPACE_INSTALL_DRUSH=false
WORKSPACE_DRUSH_VERSION=8.1.17
WORKSPACE_INSTALL_DRUPAL_CONSOLE=false
WORKSPACE_INSTALL_WP_CLI=false
WORKSPACE_INSTALL_AEROSPIKE=false
WORKSPACE_INSTALL_OCI8=false
WORKSPACE_INSTALL_V8JS=false
WORKSPACE_INSTALL_LARAVEL_ENVOY=false
WORKSPACE_INSTALL_LARAVEL_INSTALLER=false
WORKSPACE_INSTALL_DEPLOYER=false
WORKSPACE_INSTALL_PRESTISSIMO=false
WORKSPACE_INSTALL_LINUXBREW=false
WORKSPACE_INSTALL_MC=false
WORKSPACE_INSTALL_SYMFONY=false
WORKSPACE_INSTALL_PYTHON=false
WORKSPACE_INSTALL_POWERLINE=false
WORKSPACE_INSTALL_SUPERVISOR=false
WORKSPACE_INSTALL_IMAGE_OPTIMIZERS=false
WORKSPACE_INSTALL_IMAGEMAGICK=false
WORKSPACE_INSTALL_TERRAFORM=false
WORKSPACE_INSTALL_DUSK_DEPS=false
WORKSPACE_INSTALL_PG_CLIENT=false
WORKSPACE_INSTALL_PHALCON=false
WORKSPACE_INSTALL_SWOOLE=false
WORKSPACE_INSTALL_TAINT=false
WORKSPACE_INSTALL_LIBPNG=false
WORKSPACE_INSTALL_IONCUBE=false
WORKSPACE_INSTALL_MYSQL_CLIENT=false
WORKSPACE_INSTALL_PING=false
WORKSPACE_INSTALL_SSHPASS=false
WORKSPACE_INSTALL_INOTIFY=false
WORKSPACE_INSTALL_FSWATCH=false
WORKSPACE_INSTALL_YAML=false
WORKSPACE_INSTALL_MAILPARSE=false
WORKSPACE_PUID=1000
WORKSPACE_PGID=1000
WORKSPACE_CHROME_DRIVER_VERSION=2.42
WORKSPACE_TIMEZONE=UTC
WORKSPACE_SSH_PORT=2222
WORKSPACE_INSTALL_FFMPEG=false
WORKSPACE_INSTALL_WKHTMLTOPDF=false
WORKSPACE_INSTALL_GNU_PARALLEL=false
WORKSPACE_INSTALL_AST=true
WORKSPACE_AST_VERSION=1.0.3
WORKSPACE_VUE_CLI_SERVE_HOST_PORT=8008 #ここ、8080になってたので適当な番号に書き換えました!
WORKSPACE_VUE_CLI_UI_HOST_PORT=8001
WORKSPACE_INSTALL_GIT_PROMPT=false

これでコマンドをやり直したらできました!!

docker-compose up

とだけやってしまうと、容量不足になってしまい、

ERROR: Service 'web' failed to build: failed to copy files: failed to copy directory: Error processing tar file(exit status 1): open /node_modules/hosted-git-info/CHANGELOG.md: no space left on device

みたいな感じでエラーになってしまうので、立ち上げるコンテナを-dで指定しましょう。
立ち上げた後は、

laradock
$ docker-compose exec workspace bash

と打ってワークスペースに接続します。ディレクトリがroot@var/wwwみたいな感じに変わったら成功。いつもやるようにプロジェクトをコマンドを打って作りましょう。

laradock
$ composer create-project --prefer-dist laravel/laravel #アプリ名

またこれで少しの間完了するまで放置します。

root@var/www
$ ls
>laradock #アプリ名

できたらexitで接続を終了します。

laradock
$ cd nginx/sites/

最後にnginxの設定ファイルを編集します。

laradock/nginx/sites
$ cp default.conf default.conf.backup   
$ cp laravel.conf.example default.conf
$ vim default.conf
defalut.conf
server {

    listen 80;
    listen [::]:80;

    # For https
    # listen 443 ssl;
    # listen [::]:443 ssl ipv6only=on;
    # ssl_certificate /etc/nginx/ssl/default.crt;
    # ssl_certificate_key /etc/nginx/ssl/default.key;

    server_name laravel.test;
    root /var/www/laravel/#ここにアプリ名を入れる!/public;
    index index.php index.html index.htm;

laradockに戻って $docker-compose restartをして、
Docker Quickstart Terminal起動時に出るIPアドレスをブラウザで入力すると、
Laravelトップページがでます。

これで、環境構築は完了です!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

フロント・バックエンドサービスをコンテナ化してもGitコミット時にLefthookでテストやLint実行

TL;DR

  • フロント・バックエンドサービスをそれぞれコンテナ化、docker-composeで全てのコンテナを管理する
  • monorepoで管理した際に1リポジトリとなるので気軽にGit Hookの処理ができない
  • Lefthookを導入してpre-commit時にすべてのコンテナに対してLintツールを動作させるようにした

サンプルコード

https://github.com/MegaBlackLabel/lefthook-docker-node-go-dev-sample

1リポジトリで開発環境を管理したい

渋川さんの記事

マイクロサービスほどじゃないけどウェブサービスを分割開発したい人向けDocker設定を集めるスレ
https://qiita.com/shibukawa/items/fd49f98736045789ffc3

を読んでフロントエンドとAPIがごっちゃになっている開発環境ヨクナイ!ってことでサービス単位でコンテナ化してvs codeのリモートコンテナ機能を使って開発環境を再構築をしていたらGitとGItHooksの扱いで躓く。

Git Hooksの扱い

1リポジトリでサービスをコンテナ化してmonorepoを構築した際に.gitはルートディレクトリのみに存在する。
何が起こるかというと、フロントエンド開発時に「Husky+lint-stagedでコミット前にeslintやprettierを実行してコミット前にソースをチェックする」ができなくなります。これは治安が悪くなるってことで調査を進めた結果、試してみたのがLefthookです。

Lefthookを使ってみる

Lefthookとは?ということで公式の説明を引用

The fastest polyglot Git hooks manager out there

Fast and powerful Git hooks manager for Node.js, Ruby or any other type of projects.

  • Fast. It is written in Go. Can run commands in parallel.
  • Powerful. With a few lines in the config you can check only the changed files on pre-push hook.
  • Simple. It is single dependency-free binary which can work in any environment.
  • GO製。コマンドを並列実行できる
  • かんたんな設定ファイルでpre-pushのhookが使えるようになる
  • (GOによる)シングルバイナリなので、どのOSでも実行可能

今回は以下のことを実装しました。

  • 起動時にdocker-composeでインスタンス起動
  • 起動したインスタンスに対してコマンドを実施
  • 更新対象のファイルの拡張子をgrepして対象の拡張子がstageにあるときのみ実行する

※、余談ですが日本語での紹介記事は2つのみ。1つは公式の翻訳ともう一つはRubyでのHusky置き換え記事です。

Lefthook: 多機能GItフックマネージャ
https://techracho.bpsinc.jp/hachi8833/2019_10_16/79052

Git HooksマネージャーのLefthookを試してHusky(+lint-staged)と比較した結果、乗りかえました
https://blog.solunita.net/posts/change-lefthook-instead-of-lintstaged-with-husky/

Lefthookインストール

Lefthookインストールですが、公式サイトのInstallationか、リリースページから直接ダウンロードします。自分はWindows環境なのでプロジェクト内にlefthook.exeをそのまま置いて使っています。
インストール後に対象のリポジトリで以下のコマンドを実行

lefthook install #Windowsで直下に置いている場合は lefthook.exe install

インストールが完了するとリポジトリのルートに「lefthook.yml」が作成されますので、こちらに設定を書きます。

Lefthook設定ファイル解説

lefthook.yml
# EXAMPLE USAGE
# Refer for explanation to following link:
# https://github.com/Arkweid/lefthook/blob/master/docs/full_guide.md
#
# pre-push:
#   commands:
#     packages-audit:
#       tags: frontend security
#       run: yarn audit
#     gems-audit:
#       tags: backend security
#       run: bundle audit
#
# pre-commit:
#   parallel: true
#   commands:
#     eslint:
#       glob: "*.{js,ts}"
#       run: yarn eslint {staged_files}
#     rubocop:
#       tags: backend style
#       glob: "*.rb"
#       exclude: "application.rb|routes.rb"
#       run: bundle exec rubocop --force-exclusion {all_files}
#     govet:
#       tags: backend style
#       files: git ls-files -m
#       glob: "*.go"
#       run: go vet {files}
#   scripts:
#     "hello.js":
#       runner: node
#     "any.go":
#       runner: go run

pre-commit:
    piped: true
    commands:
        1_docker-compose:
            root: .
            run: docker-compose up -d
        2_eslint:
            root: "containers/frontend/"
            glob: "*.{js,jsx,ts}"
            run: docker exec -it frontend-container yarn eslint-check
        3_frontend-test:
            root: "containers/frontend/"
            glob: "*.{js,jsx,ts}"
            run: docker exec -it frontend-container yarn test
        4_api-test:
            root: "containers/api/"
            run: docker exec -it api-container go test

サンプルとインデントの数が違うのはご愛嬌。今回使っている処理は以下の通り。

  • pre-commit: コミット実施前に実行してほしい処理
  • piped:commandsを名前順に実施する。そのため頭文字に数字をつける
  • commands:実行するコマンド
  • root:どの階層でコマンドを実施するかを記載
  • glob:stagedのファイルのうち、コマンド実行対象とするファイルを選別する
  • run:実行するコマンド

コマンドの内容ですが以下の処理を実施しています。

  • docker-composeでコンテナを起動
  • docker execを使用してフロントエンドコンテナでeslint+Prettierを実施
  • docker execを使用してフロントエンドコンテナでテストを実施
  • docker execを使用してAPIコンテナでテストを実施

フォルダ・ファイル構成

以下の想定でファイル構成を行っています。
- フロントエンドとAPIサーバをそれぞれコンテナ化して管理
- docker-composeでコンテナを一元管理
- フロントエンドではeslint+Prettierでのソース整形とテストを実施
- APIサーバではテストを実施
- それぞれ正常に実行時のみコミットを実施する

ファイル構成
lefthook-docker-node-go-dev-sample
│  .gitignore
│  docker-compose.yml
│  lefthook.exe
│  lefthook.yml
│  LICENSE
│  README.md
│
└─containers
    ├─api
    │      docker-entrypoint.sh
    │      Dockerfile
    │      go.mod
    │      go.sum
    │      main.go
    │      main_test.go
    │
    └─frontend
        │  .eslintrc.json
        │  docker-entrypoint.sh
        │  Dockerfile
        │  package.json
        │  README.md
        │  yarn.lock
        │
        ├─node_modules
        ├─public
        │      favicon.ico
        │      index.html
        │      logo192.png
        │      logo512.png
        │      manifest.json
        │      robots.txt
        │
        └─src
                App.css
                App.js
                App.test.js
                index.css
                index.js
                logo.svg
                serviceWorker.js
                setupTests.js

Lefthookでpre-commit時にコンテナに対してコマンド実行

pre-commitをrunしてみる。

実行結果
.\lefthook.exe run pre-commit
RUNNING HOOKS GROUP: pre-commit

  EXECUTE > 1_docker-compose
api-container is up-to-date
frontend-container is up-to-date

  EXECUTE > 2_eslint
yarn run v1.22.4
$ eslint --print-config .eslintrc.json | eslint-config-prettier-check
No rules that are unnecessary or conflict with Prettier were found.
Done in 0.69s.

  EXECUTE > 3_frontend-test
yarn run v1.22.4
$ CI=true react-scripts test
PASS src/App.test.js
  ✓ renders learn react link (39ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        2.081s
Ran all test suites.
Done in 3.23s.

  EXECUTE > 4_api-test
[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

[GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.
 - using env:   export GIN_MODE=release
 - using code:  gin.SetMode(gin.ReleaseMode)

[GIN-debug] GET    /ping                     --> github.com/MegaBlackLabel/lefthook-docker-node-go-dev-sample.setupRouter.func1 (3 handlers)
[GIN] 2020/03/15 - 03:43:28 | 200 |      44.742µs |                 | GET      /ping
PASS
ok      github.com/MegaBlackLabel/lefthook-docker-node-go-dev-sample    0.014s

SUMMARY: (done in 7.78 seconds)
✔️  1_docker-compose
✔️  2_eslint
✔️  3_frontend-test
✔️  4_api-test

コマンドが順番に実行されそれぞれの実行結果が表示。最後にサマリーとしてOK・NGが出力されます。

まとめ

  • サービス単位でコンテナ化して開発するのは便利だね。でもGit Hooksの処理ができない
  • Lefthook使えばできるよ。シングルバイナリだから導入もかんたんだよ
  • コンテナ化してもGit Hooksが使えるので複数の開発者がいても治安が維持できそう

以上

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerコンテナ上で動くGinサーバーにアクセスできないエラーの解決法

概要

GolangのWebフレームワークであるGinを使ったAPIサーバーを、Dockerコンテナ上にデプロイして動かそうとしたところ、APIにアクセスできずかなり長い時間悩まされました。

結果的には、Ginサーバーのコードの書き方の問題だったことが分かったのですが、解決方法を念のためここにメモしておきます。

ちなみに、このエラーはWindows10及びAWS上のUbuntuサーバー(t2.small)で起こりました(尤も、実行環境はこのエラーの発生にあまり関係ないようでしたが)。

状況

Ginを用いたAPIサーバーを立てようとしていました。まだ環境構築の段階なので、コードは以下のようなモックのものになっています。

package main

import (
    "log"
    "os"
    "github.com/gin-gonic/gin"
)

func main() {
    logConfig()

    r := gin.Default()
    r.GET("/accounting-api", func(c *gin.Context) {
        log.Println("GET")
        c.JSON(200, gin.H{
            "state": "success",
        })
    })
    r.DELETE("/accounting-api", func(c *gin.Context) {
        log.Println("DELETE")
        c.JSON(200, gin.H{
            "state": "success",
        })
    })
    log.Println("Start Server")
    r.Run()
}

func logConfig() {
    logFile, _ := os.OpenFile("log/log.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
    log.SetOutput(logFile)
    log.SetFlags(log.LstdFlags | log.Lmicroseconds | log.Lshortfile)
    log.SetPrefix("[LOG] ")
}

単純に、GETDELETEメソッドで特定のパスへのリクエストが来たら、{"state": "success"}というjsonを返すだけのサーバーです。

そして、このサーバーを動かすためのDockerfileが以下です。

FROM golang:alpine
RUN apk update && apk add --no-cache git
RUN go get -u github.com/gin-gonic/gin && mkdir /usr/src && mkdir /usr/src/api
COPY ./api /usr/src/api
WORKDIR /usr/src/api
CMD ["go","run","main.go"]

ホスト上のapiというディレクトリには上記のGoファイル等があるため、それをコンテナ上にコピーして、サーバーを立ち上げます。このDockerfileをapiという名前でビルドして、それを以下のコマンドで立ち上げました。

docker run -p 8083:8080 api

ホスト上のポート8083をコンテナ上のポート8080にマッピングしています。上記のコマンドを実行すると、以下のような出力がなされ、Ginサーバーが立ち上がっていることが確認できます。

[GIN-debug] GET    /accounting-api           --> main.main.func1 (3 handlers)
[GIN-debug] DELETE /accounting-api           --> main.main.func4 (3 handlers)
[GIN-debug] Environment variable PORT is undefined. Using port :8080 by default
[GIN-debug] Listening and serving HTTP on localhost:8080

ポートを指定しなかったので、デフォルトでポート8080で動いています。このように一見ちゃんと動いているようにも見えますが、ホスト側でhttp:localhost:8083にcurlでアクセスしてみても、以下のようにエラーが出てしまいました。

curl: (52) Empty reply from server

エラー解消のため試みたこと

1. コンテナの中に入って、APIにアクセスできるか確認

まず最初に、コンテナ上で本当にGoのプログラムがちゃんと動いているのかを確認します。そのために立ち上げたdockerコンテナの中に入ってみます。

# apiサーバーの動くコンテナの中に入る
docker exec -it api /bin/ash

このコンテナのベースとなっているAlpineには/bin/bashがなかったので、/bin/ashを使います。そして以下のコマンドを打って、ちゃんとプログラムが動いているのか確かめます。

# そもそもcurlが入っていないので、インストールする
apk add --no-cache curl
# 念のためプロキシを無効にして、curlでapiサーバーにアクセスする
curl -x "" http://localhost:8080/accounting/api

curlの実行結果がこちら。

{"state": "success"}

ちゃんと結果が取れています。なので、コンテナ上ではちゃんとGinサーバーのプログラムが動いているようです。

2. DockerfileでポートをEXPOSE

コンテナ上ではプログラムは動いているようなので、次はポートマッピングの部分がうまくいっていないのではないかと疑ってみます。調べてみるとDockerfileにはEXPOSEというコマンドが書けるようなので、追加してみます。

EXPOSE 8080

これをやっても、解決しませんでした。

そもそも公式ドキュメントによると、EXPOSEコマンドは実際は何の働きもせず、特定のポートを開放する旨を開発者に知らせるための、ドキュメントのような役割しかもっていないようです。なので、EXPOSEコマンドをつけただけで問題が解決するはずがありませんでした。

3. Windowsのファイアウォールの設定の確認

開発は基本的にWindows上のDockerで行っていたため、Windowsのファイアウォールの設定を見直してみましたが、これも意味がありませんでした。

そもそも、このDockerfileをUbuntu上でビルドして立ち上げてみても、同様にAPIサーバーにアクセスできなかったため、最初からなんとなくWindowsのファイアウォールのせいではないことが分かっていましたが。

4. (これで解決)Ginサーバー側でポートの指定

Goのプログラムの中で、GInサーバーを立ち上げる部分でポートを指定するようにしたところ、上手くアクセスできるようになりました。具体的には、以下の部分です。

r := gin.Default()
r.Run(":8080")

何も指定しなくてもデフォルトで8080で立ち上がるため気にしていなかったのですが、しっかりと指定しないとどうやらダメなようです。

なぜポートはデフォルトではダメで、明示的に記さなければならないかは、よくわかりません。分かったら追記します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelの開発環境をDockerで構築したらcould not find driver

Laravelの開発環境をDockerで構築しようとしてハマったのでメモを残しておきます。

Laravelの開発環境をDockerで構築する方法は以下を参照してください。
Dockerを使って1コマンドで起動できるLaravel開発環境を構築する

以下のようにDockerfileを作成しました。

Dockerfile
FROM php:7.3-apache

COPY --from=composer /usr/bin/composer /usr/bin/composer
RUN apt-get update && apt-get install -y \
    unzip \
    libzip-dev \
    zlib1g-dev \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* \
    && a2enmod rewrite
COPY ./apache2.conf /etc/apache2/apache2.conf
COPY ./php.ini /usr/local/etc/php/php.ini

WORKDIR /var/www/myapp

コンテナを起動してアクセスしてみると、PDOExceptionでcould not find driverが出力されました。
MySQLのPDOドライバが有効になってなかったかと思って、php.iniのexentionのコメントを外すもエラー消えず。

そもそもインストールされてないっぽいです。
対処法はDocker Hub に答えがありました。

======Docker Hub引用=========
PHP Core Extensions
For example, if you want to have a PHP-FPM image with the gd extension, you can inherit the base image that you like, and write your own Dockerfile like this:

FROM php:7.4-fpm
RUN apt-get update && apt-get install -y \
        libfreetype6-dev \
        libjpeg62-turbo-dev \
        libpng-dev \
    && docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install -j$(nproc) gd

======Docker Hub引用=========

どうやらdocker-php-ext-installでいけるようです。

最終的にこんな形にして、エラーは解消しました。

FROM php:7.3-apache

COPY --from=composer /usr/bin/composer /usr/bin/composer
RUN apt-get update && apt-get install -y \
    unzip \
    libzip-dev \
    zlib1g-dev \
    && docker-php-ext-install \
    zip \
    pdo_mysql \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/* \
    && a2enmod rewrite
COPY ./apache2.conf /etc/apache2/apache2.conf
COPY ./php.ini /usr/local/etc/php/php.ini

WORKDIR /var/www/myapp
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Windows10 Pro×VSCode×Dockerでお手軽Pythonデータ分析環境構築

概要

環境構築、嫌いですよね?
私はエラーを出しまくって平気で数日かけてしまうダメ人間なので、発狂するレベルで嫌いです。
弱小ながらも一応エンジニアの私が発狂するような作業を一緒に分析業務を行う非エンジニアにやらせようとしたら、背後から刺されかねない。
というわけで、多少は流用できそうかなというレベルの表題のものを作ったので、備忘録も兼ねて載せます。

非エンジニアにVSCode上でJupyter NotebookライクにPythonを書ける環境を提供する

ことを目標としています。

こんな人が読むと良いかも

  • お手軽にPython環境を作りたい
  • Visual Studio Codeをメインに使いたい
  • 環境構築なんぞに労力を割きたくない
  • 非エンジニアにも手軽にPythonを使ってデータ分析をしてもらいたい
  • できることならマウスポチポチだけしかしたくない(させたくない)

(各ソフトウェアや技術詳細の説明はしていません)

前提環境

OS:Windows 10 Pro 64bit(Docker使用時にHyper-V機能を利用するため)

環境構築

大まかに、以下の流れ。
1. 環境のベースとなるフォルダ構成取得
2. Docker Desktop for Windowsのインストールとセットアップ
3. Visual Studio Codeのインストールとセットアップ
4. 環境作成

1. 環境のベースとなるフォルダ構成取得

GitHubにベースに使うフォルダ構成と必要なファイル群を用意したので、こちらをCloneするなりダウンロードするなりして任意のフォルダに配置(私の場合はCドライブ配下にGit用フォルダを作成)
https://github.com/m0p1nt/ds_base_env_for_vscode

お好みでdevcontainer.jsonのname属性の値を変更。
image.png

2. Docker Desktop for Windowsのインストールとセットアップ

環境構築はすでに他の投稿者さんがわかりやすい記事を書いてくださっているので、大まかな手順のみ(参考サイトは後述の補足にて)。

1) Hyper-Vの有効化
コントロールパネル -> プログラムと機能 -> Windows の機能の有効化または無効化の項目群にあるHyper-vのチェックをオンにする(再起動を求められたら再起動する)。
image.png

2) Docker Desktop for Windowsダウンロードサイトよりインストーラをダウンロードしてインストール
image.png

3) ドライブのマウント設定

(1)Widndowsタスクバー右下Dockerアイコンより[Setting]で設定画面を開く(アイコンがない場合はDockerを起動してから再度確認)。
image.png

(2)分析環境用のフォルダを配置したドライブに対するマウント許可にチェックを入れる
image.png

3. Visual Studio Codeのインストールとセットアップ

1)Visual Studio Codeダウンロードサイトよりインストーラをダウンロードしてインストール

2)拡張機能Remote - Containersを追加
image.png

4. 環境作成

1)VSCodeの画面左下の緑色のアイコンをクリックし、Remote-Containers: Open Folder in Container...を選択。
image.png

上記「1. 環境のベースとなるフォルダ構成取得」で配置したフォルダを選択。
image.png

新規画面が立ち上がり環境構築が始まるので数分待つとできあがり。
image.png

VSCode上でJupyter Notebookライクな使い方ができるので便利。
image.png

閉じるときは、左下の緑色のアイコンをクリックし、リモート接続を終了するを選択。
image.png

補足

  • Pythonライブラリを追加したくなったら
    →VSCodeのターミナル上でpipコマンドでインストール
    image.png
    他の人にライブラリの追加を反映させたい場合はVSCodeのターミナル上で、
    $ pip freeze > .devcontainer/requirements.txt
    でインストール済みのライブラリを一覧化できる。

  • VSCodeの拡張機能を追加したくなったら
    devcontainer.jsonのextensions属性を編集する
    image.png
    名称は、拡張機能検索時に表示される下図の値が該当。
    (例:拡張機能Pythonの場合)
    image.png

参考にしたもの

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Docker】データボリュームをバックアップ→リストア

データが入ったDBがあると仮定して話を進めます。

ボリュームと紐づいているコンテナの名前を確認

$ docker container ls
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
7b6a79314721        sample-app_web       "/bin/sh -c 'rm -f t…"   5 minutes ago       Up 5 minutes        0.0.0.0:3000->3000/tcp   sample-app_web_1
2ed21c2aac12        postgres            "docker-entrypoint.s…"   5 minutes ago       Up 5 minutes        0.0.0.0:5434->5432/tcp   sample-app_db_1

NAMESを参照。今回の場合はsample-app_db_1

コンテナをストップ

$ docker-compose stop

バックアップ

docker run --rm --volumes-from sample-app_db_1 -v `pwd`:/backup busybox tar cvf /backup/backup.tar /var/lib/postgresql/data

Postgresqlの場合の例です。
sample-app_db_1の部分に、先ほどのステップで確認したコンテナ名を設定
mysplの場合/var/lib/postgresql/dataの部分を/var/lib/mysqlに変更

(mysqlの場合)
$ docker run --rm --volumes-from sample-app_db_1 -v `pwd`:/backup busybox tar cvf /backup/backup.tar /var/lib/mysql

コンテナとボリュームを削除→コンテナを再作成

$ docker-compose down --volumes
$ docker-compose up -d

コンテナをストップ

$ docker-compose stop

リストア

$ docker run --rm --volumes-from sample-app_db_1 -v `pwd`:/backup busybox tar xvf /backup/backup.tar

(mysqlの場合)

同じ
$ docker run --rm --volumes-from sample-app_db_1 -v `pwd`:/backup busybox tar xvf /backup/backup.tar

最後に

本当はこの方法より、SQLによるダンプでバックアップを取るほうが望ましいらしいです。

まだ検証できていないので、興味がある方はご自身で調べてみてください。

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WSL2+docker+PHPのWindows開発環境構築(3) PHPStorm編

本ページに直接来た方はWSL2+docker+PHPのWindows開発環境構築(1) WSL2編から読んでね。

ヾ(・ω<)ノ" 三三三● ⅱⅲ コロコロ♪


------------------- ↓ 余談はここから ↓-------------------

関連記事:

前回docker起動までいけた。
あとはPHPStormと繋げれば良い。

('ω')ノ あとすこしやで


------------------- ↓ 本題はここから ↓-------------------

Dockerの調整

タスクバーのdockerアイコンから「setting」を選択
以下にチェックを入れて「Appli&Restart」

  • Expose daemon on tcp://localhost:2375 without TLS

キャプチャ-202003091735.JPG

PHPStormの調整

Pluginのインストール

兎にも角にもプラグイン。
DockerPHP Dockerをインストール

[File]-[Setting]-[Plugins]から以下の二つをインストール

  • Docker
  • PHP Docker

キャプチャ-202003091743.JPG

(PHP Remote Interpreterってのも一緒に入る)

Docker Pluginの設定

「Build, Execution, Deployment」-「Docker」-「+」を押下
「TCP socker」にチェックを入れて「OK」を押下

キャプチャ-202003091744.JPG

PHP Pluginの設定

「Languages & Frameworks」-「PHP」-「Cli Interpreter」-「...」を押下

キャプチャ-202003091751.JPG

「Cli Interpreters」欄の「+」を押下、
「From Docker, Vagrant, Vm, WSL, Remote...」を押下する。

キャプチャ-202003091755.JPG

「Image Name」欄の「▼」を押し、
「laradock_php-fpm:latest」を選択

キャプチャ-202003141546.JPG

コード補完が効いていたら成功だ。
これで実際の開発に入ることができるだろう。
(゜-゜) こんなに頑張らないと物作れないってどうなんだろ・・・。

このあとGitやらXdebugやら使うことになると思うが、
それは一般的なものなので今回は省く。
(過去記事のどれかでやったっけな。)


------------------- ↓ 後書はここから ↓-------------------
これだけやって、
ようやく使えるDockerってどうなの?
(ワイだけかな)
まぁ、AWSのデプロイ考えたらdockerなのかなぁ。
ほかの方法だとイメージを量産する感じになっちゃうし。
環境を作るって観点だけで物事を考えたらいかんか。

今回はlaradockでやったけど、
これがなければ環境作りだけで時間を食い潰してただろうな。
いまいちDocker Hubの扱い方がよくわからない。

MySQLが起動しない

PHPとは関係ないが、
Dockerがらみ。
DockerコンテナでMySQLだけが起動しない。

$ docker-compose up -d --build mysql

シーン・・・。

(?_?) アレ?
ログ見てみよう。

2020-03-14 18:48:39+09:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.19-1debian10 started.
2020-03-14 18:48:39+09:00 [Note] [Entrypoint]: Initializing database files
2020-03-14T09:48:39.973002Z 0 [Warning] [MY-011070] [Server] 'Disabling symbolic links using --skip-symbolic-links (or equivalent) is the default. Consider not using this option as it' is deprecated and will be removed in a future release.
2020-03-14T09:48:39.973444Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 8.0.19) initializing of server in progress as process 22
2020-03-14T09:48:39.986553Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /var/lib/mysql/ is case insensitive
mysqld: Cannot change permissions of the file 'ca.pem' (OS errno 1 - Operation not permitted)
2020-03-14T09:48:45.126054Z 0 [ERROR] [MY-010295] [Server] Could not set file permission for ca.pem
2020-03-14T09:48:45.126403Z 0 [ERROR] [MY-013236] [Server] The designated data directory /var/lib/mysql/ is unusable. You can remove all files that the server added to it.
2020-03-14T09:48:45.126758Z 0 [ERROR] [MY-010119] [Server] Aborting
2020-03-14T09:48:46.659592Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.19) MySQL Community Server - GPL.

|ω・) ナニコレ

データディレクトリをいったん削除してもう一回起動

2020-03-14 18:48:39+09:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.19-1debian10 started.
2020-03-14 18:48:39+09:00 [Note] [Entrypoint]: Initializing database files
2020-03-14T09:48:39.973002Z 0 [Warning] [MY-011070] [Server] 'Disabling symbolic links using --skip-symbolic-links (or equivalent) is the default. Consider not using this option as it' is deprecated and will be removed in a future release.
2020-03-14T09:48:39.973444Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 8.0.19) initializing of server in progress as process 22
2020-03-14T09:48:39.986553Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /var/lib/mysql/ is case insensitive
mysqld: Cannot change permissions of the file 'ca.pem' (OS errno 1 - Operation not permitted)
2020-03-14T09:48:45.126054Z 0 [ERROR] [MY-010295] [Server] Could not set file permission for ca.pem
2020-03-14T09:48:45.126403Z 0 [ERROR] [MY-013236] [Server] The designated data directory /var/lib/mysql/ is unusable. You can remove all files that the server added to it.
2020-03-14T09:48:45.126758Z 0 [ERROR] [MY-010119] [Server] Aborting
2020-03-14T09:48:46.659592Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.19) MySQL Community Server - GPL.
2020-03-14 18:53:21+09:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.19-1debian10 started.
2020-03-14 18:53:21+09:00 [Note] [Entrypoint]: Initializing database files
2020-03-14T09:53:21.968144Z 0 [Warning] [MY-011070] [Server] 'Disabling symbolic links using --skip-symbolic-links (or equivalent) is the default. Consider not using this option as it' is deprecated and will be removed in a future release.
2020-03-14T09:53:21.969067Z 0 [System] [MY-013169] [Server] /usr/sbin/mysqld (mysqld 8.0.19) initializing of server in progress as process 22
2020-03-14T09:53:21.987587Z 0 [Warning] [MY-010159] [Server] Setting lower_case_table_names=2 because file system for /var/lib/mysql/ is case insensitive
2020-03-14T09:53:27.708440Z 0 [ERROR] [MY-010295] [Server] Could not set file permission for ca.pem
2020-03-14T09:53:27.708719Z 0 [ERROR] [MY-013236] [Server] The designated data directory /var/lib/mysql/ is unusable. You can remove all files that the server added to it.
2020-03-14T09:53:27.709077Z 0 [ERROR] [MY-010119] [Server] Aborting
2020-03-14T09:53:29.169116Z 0 [System] [MY-010910] [Server] /usr/sbin/mysqld: Shutdown complete (mysqld 8.0.19) MySQL Community Server - GPL.

( ゚Д゚)ハァ? 余計悪化した。。。
ちょっと掘り下げてみるか。。。

permissionって書いてあるから権限回りだろう・・・( ゚д゚)ハッ!
そういえばこのDocker設定作ったのはMac野郎だった。

docker-compose.yml
  mysql:
    image: mysql:8.0
    ports:
      - 3306:3306
    user: "500:500"
    volumes:
・・・・

やっぱり。
WSL上のuserIDとdocker上のuserIDがあってない。
WSL上のUIDを確認してみよう。

C:\> wsl
$ id
uid=1000(dozo) gid=1000(dozo) groups=1000(dozo),・・・

docker-compose.ymlを調整

docker-compose.yml
  mysql:
    image: mysql:8.0
    ports:
      - 3306:3306
    user: "1000:1000"
    volumes:
・・・・

Mysqlのデータを全削除。
イメージを削除して、コンテナを再構成

$ rm -Rf /mnt/c/Users/magic/mysql/data/*
$ docker rm bc57ea450000
bc57ea450000
$ docker rmi 9b51d9270000
Untagged: mysql:8.0
Untagged: mysql@sha256:4a30434ce03d2fa39
・・・
79e9d07a19e3a8d49010ab9c98a2c348fa116c87
$ docker-compose up -d --build mysql
Creating laradock_mysql_1 ... done

直った・・・。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Amazon LinuxにKubernetes環境構築【kubeadm】

前提

EC2でAmazonLinuxインスタンスを作成してあること(CPUとメモリは最低でも2以上を要求されるのでt2.microではダメ)

背景

当たり前のようにkubernete環境構築で詰まったので手順をメモ

環境

2020/3月時点でのバージョン

[root@kube-master work]# kubectl version
Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.4", GitCommit:"8d8aa39598534325ad77120c120a22b3a990b5ea", GitTreeState:"clean", BuildDate:"2020-03-12T21:03:42Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.4", GitCommit:"8d8aa39598534325ad77120c120a22b3a990b5ea", GitTreeState:"clean", BuildDate:"2020-03-12T20:55:23Z", GoVersion:"go1.13.8", Compiler:"gc", Platform:"linux/amd64"}

事前準備

  1. host名の設定/hostsファイル編集
  2. Dockerのインストール
  3. swapの無効化
  4. SELinuxを止める(本番環境ではやらないほうがいいらしい)
  5. iptables編集
  6. Dockerのkubelet向けcgroup設定

host名の設定

# いちおうrootユーザーになっとく
[ec2-user@ip-10-0-10-176 ~]$ sudo su -
[root@kube-master ~]# hostnamectl set-hostname kube-master
[root@kube-master ~]# echo "[your aws ec2 public ipaddress] kube-master" >> /etc/hosts
[root@kube-master ~]# cat /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost6 localhost6.localdomain6
3.112.45.181 kube-master

Dockerインストール

[root@kube-master ~]# yum update -y
[root@kube-master ~]# yum install -y docker
[root@kube-master ~]# systemctl enable docker && systemctl start docker

インストールの確認

[root@kube-master ~]# docker info | grep -i version
Server Version: 18.09.9-ce
containerd version: 894b81a4b802e4eb2a91d1ce216b8817763c29fb
runc version: 2b18fe1d885ee5083ef9f0838fee39b62d653e30
init version: fec3683
Kernel Version: 4.14.171-136.231.amzn2.x86_64

[root@kube-master ~]# docker info | grep -i driver
Storage Driver: overlay2
Logging Driver: json-file
Cgroup Driver: cgroupfs # あとでここ変える

swapの無効化

swap無効化し、swap領域が使われていないことを確認する。

公式サイトにswap無効化してくださいと書かれている(Swap disabled. You MUST disable swap in order for the kubelet to work properly.)

[root@kube-master ~]# swapoff -a
[ec2-user@ip-10-0-10-176 ~]$ free
              total        used        free      shared  buff/cache   available
Mem:        8166360      224408     7181288         484      760664     7695804
Swap:             0           0           0

SELinuxを止める

以下の理由により

Setting SELinux in permissive mode by running setenforce 0 and sed ... effectively disables it. This is required to allow containers to access the host filesystem, which is needed by pod networks for example. You have to do this until SELinux support is improved in the kubelet.

[ec2-user@ip-10-0-10-176 ~]$ setenforce 0
setenforce: SELinux is disabled
[root@kube-master ~]# sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config

sysctlでネットワークをブリッジできるようする

Some users on RHEL/CentOS 7 have reported issues with traffic being routed incorrectly due to iptables being bypassed. You should ensure net.bridge.bridge-nf-call-iptables is set to 1 in your sysctl config, e.g.

[root@kube-master ~]# cat <<EOF > /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
[root@kube-master ~]# sysctl --system

Dockerのkubelet向けcgroup設定

DockerのcgroupDriverをsystemdに設定する

[root@kube-master ~]# cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true"
  ]
}
EOF
[root@kube-master ~]# mkdir -p /etc/systemd/system/docker.service.d
[root@kube-master ~]# systemctl daemon-reload
[root@kube-master ~]# systemctl restart docker
[root@kube-master ~]# docker info | grep -i driver
Storage Driver: overlay2
Logging Driver: json-file
Cgroup Driver: systemd

kubernetesインストール

  1. Kubernetesのリポジトリ登録
  2. kubelet/kubeadm/kubectlインストール
  3. kubeadm init
  4. CNI構築
  5. all-in-one化

Kubernetesのリポジトリ登録

公式のものを参考に

[root@kube-master ~]# cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF

kubelet/kubeadm/kubectlインストール

[root@kube-master ~]# yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
[root@kube-master ~]# systemctl enable kubelet && systemctl start kubelet
Created symlink from /etc/systemd/system/multi-user.target.wants/kubelet.service to /usr/lib/systemd/system/kubelet.service.

kubeadm実行

公式サイトを参考に実行していく
CNIにはCalicoを選択

[root@kube-master ~]# kubeadm init --pod-network-cidr=192.168.0.0/16
[root@kube-master ~]# kubectl apply -f https://docs.projectcalico.org/v3.8/manifests/calico.yaml

initが成功したらkubeadmの指示に従う

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

[root@kube-master ~]# mkdir -p $HOME/.kube
[root@kube-master ~]# cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
[root@kube-master ~]# chown $(id -u):$(id -g) $HOME/.kube/config

kubeadm join --token ~~はall-in-one構成では必要ないらしいのでやらない

calicoネットワーク構築

[root@kube-master ~]# kubectl apply -f https://docs.projectcalico.org/v3.8/manifests/calico.yaml

kubernetesのall-in-one構築

kubectl taint nodes --all node-role.kubernetes.io/master-

動作確認

[root@kube-master ~]# kubectl get all --all-namespaces
NAMESPACE     NAME                                           READY   STATUS    RESTARTS   AGE
kube-system   pod/calico-kube-controllers-5c45f5bd9f-74f4h   1/1     Running   0          4m32s
kube-system   pod/calico-node-mmvqh                          1/1     Running   0          4m33s
kube-system   pod/coredns-6955765f44-45mkb                   1/1     Running   0          16m
kube-system   pod/coredns-6955765f44-xntv5                   1/1     Running   0          16m
kube-system   pod/etcd-kube-master                           1/1     Running   0          16m
kube-system   pod/kube-apiserver-kube-master                 1/1     Running   0          16m
kube-system   pod/kube-controller-manager-kube-master        1/1     Running   0          16m
kube-system   pod/kube-proxy-d2qmc                           1/1     Running   0          16m
kube-system   pod/kube-scheduler-kube-master                 1/1     Running   0          16m

NAMESPACE     NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
default       service/kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP                  16m
kube-system   service/kube-dns     ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   16m

NAMESPACE     NAME                         DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                 AGE
kube-system   daemonset.apps/calico-node   1         1         1       1            1           beta.kubernetes.io/os=linux   4m34s
kube-system   daemonset.apps/kube-proxy    1         1         1       1            1           beta.kubernetes.io/os=linux   16m

NAMESPACE     NAME                                      READY   UP-TO-DATE   AVAILABLE   AGE
kube-system   deployment.apps/calico-kube-controllers   1/1     1            1           4m34s
kube-system   deployment.apps/coredns                   2/2     2            2           16m

NAMESPACE     NAME                                                 DESIRED   CURRENT   READY   AGE
kube-system   replicaset.apps/calico-kube-controllers-5c45f5bd9f   1         1         1       4m34s
kube-system   replicaset.apps/coredns-6955765f44                   2         2         2       16m

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DockerのDの字も分からない状態を抜け出すためにやって良かったことをまとめてみる

概要

Dockerを触っていく上で、何を勉強したら良いかで行き詰まることが多かったので、勉強していて特に役に立ったな、と思ったものを備忘録がてら整理してみます。

対象読者

Dockerに入門したはいいけれど、インフラもLinuxも全然わからん、でも何とかしたい、というレベルの話が中心となっています。
k8sまで踏み込んだり、Dockerをバリバリ実務で使いこなすためのベストプラクティスなどなど、深い部分は対象外としています。むしろ、そういうのがあったら読みたいです。

また、本記事では、Webアプリの実行環境をDockerで構築できるようになるために必要な知識にフォーカスしています。そのため、データベースを利用した簡単なWebアプリをつくった経験があると、Dockerを勉強するモチベーションが高まるかもしれません。

前置き

1年ほど前に、ふとしたきっかけで、Dockerやるかと思い立ちます。Dockerは入門記事が充実しており、見よう見まねでとりあえず動かせないこともないところまでは、サクッと進みました。
しかし、当時はLinuxやインフラ系の知識が皆無だったこともあり、動作原理どころか、そもそも自分が何をやっているのかも曖昧で、入門から先は手も足も出ませんでした。

Dockerそのものの入門記事は数多くありましたが、Dockerを理解するためにどんな知識が必要かの全体像がまとまっているものは、中々見つけられませんでした。
Dockerは私にはまだ早いなぁ...と思い、でもやっぱりDockerわかるようになりたいなぁ...と気にかけながら、あれこれ色々手を出し、勉強していました。

まだまだDocker完全に理解した状態には程遠いですが、基本部分の理解に必要な前提知識はそれなりに補強できたのか、Dockerの動作が全くイメージできていない状態からは、なんとか脱出できた...はずです。


Dockerなんもわからん状態を辛うじて抜け出せたとはいえ、何をどこまでやれば、Dockerの苦手意識をなくせるかが分からず、手探りの状態が続くのは中々にしんどかったです。
ですので、備忘録がてら、これはやっておいて良かったな、と思ったものをまとめておこうと思います。
これさえやれば、Dockerはもう完璧!!...なんてことはありませんが、なにかの参考になれば幸いです。

以下では、本を中心に紹介していきます。このとき、それぞれについて、何を学ぶことを目的とするかを意識しておくとよいかもしれません。
目安となるかは分かりませんが、以下はやって良かったことの紹介に加え、何を学ぶことを目指して取り組んだかも、あわせて記述していきます。

Linux

コンテナ内での操作はもちろんのこと、Dockerの仕組みを学ぶ上では、何よりLinuxの理解が欠かせません。
とは言え、Linux単体だけを見ても勉強する内容は非常に幅広く、何から手をつけるべきか、悩みやすい部分でもあります。
以下では、基礎的なコマンドや、コンテナ内の操作、そして、Dockerの動作原理を理解する上で、助けられた書籍を挙げていきます。

新しいLinuxの教科書

  • 学べること: シェルを中心としたLinuxの基本知識・コマンド

元々Linuxを扱う機会はぽつぽつとありましたが、書籍を利用してじっくり学ぶのは、これが初めてとなりました。
結論から言うと、最初にこの書籍から始めたのは、大正解だったと思っています。シェルとはなんぞやから始まり、雰囲気でなんとなく使っていたコマンドについて、一つ一つ丁寧に知識を積み上げるような形で紹介されているため、とても読みやすいです。

コンテナの中での操作は、大抵の場合、Linuxのシェル操作が前提知識として必須になります。まずはここからスタートすれば、コンテナに入っても何をしたらいいか分からず、しんどい思いをすることもなくなるかと思います。
Linuxの基礎がぎゅっと詰まっているので、これからも定期的に読み返していきたいと思います。


ゼロからはじめるLinuxサーバー構築・運用ガイド 動かしながら学ぶWebサーバーの作り方

  • 学べること: シェル操作によるアプリケーション実行環境の構築方法

Dockerを学習するメリットとして、環境構築が容易になることがよく挙げられます。これを実感してこそ、Dockerを学ぶモチベーションも高まってきます。

そこで、シェル操作に慣れてきたところで、実際に本をベースに、手を動かしながら環境構築をやってみました。今のご時世なら、VPSやクラウドサービスなどを活用すれば、安価にサーバを構築することができます。
勉強がてら、まずはコンテナではなく、実際にサーバとして構築してみるとよいかと思います。
セキュリティ面で不安がある場合は、VMを利用してみるのもよいかもしれません。

この本は、サーバ構築に必要な知識を補強しながら、LAMP環境をつくり上げるまでを学べる構成になっています。あいだにネットワークの話が入り、そこでも説明はされていますが、もし詰まった場合は、先にネットワークを勉強してから再挑戦すると、つらくないかもしれません。


試して理解Linuxのしくみ ~実験と図解で学ぶOSとハードウェアの基礎知識

  • 学べること: カーネルを中心とした、Linuxの各種機能の基本動作原理

Dockerはkernelを共有する

なんて言葉があるように、Dockerを深く知るには、カーネルの理解が重要です。しかし、カーネルを理解するためには、幅広い分野の深い知識・経験が必要となります。
カーネルをしっかり学習するのであれば、難しくて分厚い本に立ち向かう覚悟を持たなければなりませんが、Dockerに入門する段階であれば、こういった入門書1冊でも十分だと思います、きっと...。

少し話は逸れましたが、この本は、難しい概念を、豊富な図で分かりやすく説明されています。文章で少し迷子になっても、すぐにイメージを補強するための図で補ってくれるため、難しい本でよくある途中リタイアを防いでくれることでしょう。

更に、図解だけにとどまらず、プロセス管理やメモリ管理などを、実際にC言語で書かれたサンプルコードによって、イメージをコードと結びつけながら学ぶことができます。
この結びつきは、時間の掛かることではありますが、ただ字面を追っただけでは得られないレベルまで、理解を深めてくれます。

実際にこの本を読んだあとでは、Dockerの動作原理がかなりイメージしやすくなりました。メモリ管理の辺りからぐんぐん難易度が上がっていきますが、じっくり取り組む価値はおおいにあると思います。

※1 C言語自体の勉強は、苦しんで覚えるC言語がわかりやすくておすすめです。
※2 前半部分で既に難易度が高いと感じる場合は、「プログラムはなぜ動くのか」・「コンピュータはなぜ動くのか」を読んでおくと、立ち向かいやすくなるかもしれません


ネットワーク

Dockerを扱う際、コンテナ間通信のイメージが掴みづらく、最初の頃は理解に苦戦していました。
当時はネットワーク関連の知識が非常に浅く、また、業務で携わる機会もほとんどなかったため、個人的に一番つまずいた部分だと感じています。

ネットワークそのものは言わずもがな、勉強する範囲が非常に広いです。ですが、Dockerのネットワークまわりを理解するのが目的であれば、レイヤー2とレイヤー3を中心に勉強すると、とっつきやすくなるかもしれません。

3分間ネットワーク基礎講座

  • 学べること: レイヤー1~3を中心とした、ネットワーク関連の各用語の概要

ウェブサイトで公開されているものの書籍版です。レイヤー1〜レイヤー3を中心に、対話形式で各種用語について、図を交えながら書かれています。
ネットワーク関連の書籍を読んでいて、この辺りのレイヤーは、業務や趣味でも触る機会が中々なく、概要を理解するのに苦労していました。特に、最初の頃は、イーサネットの規格や、物理学のあれこれの話など、深く踏み入った話とあわせて解説されると、戸惑ってしまうことがよくありました。

対して、この書籍は、踏み込み過ぎず、かつ、浅すぎず、丁度いい塩梅で各用語について書かれているので、最初の一歩におすすめです。サクッと読める文量なので、まずはネットワーク関連の用語に慣れるためにも、数回繰り返し読んでみるのもありかもしれません。また、ウェブサイト版も書籍版とは色々異なる部分があるので、興味があったら目を通してみてください。

パケットキャプチャの教科書

  • 学べること: パケットと、図解による、ネットワーク通信の流れの具体的なイメージ

たとえばプログラムであれば、文法を学んだ後、実際にソースコードを書くことで、経験を通じて知識を定着させることができます。しかし、ネットワークに関しては、実際の通信を覗いたり、操作するための道程は、プログラムを書くときほど情報が充実しているとは言えません。

そんな中、この書籍に出会うことで、ネットワークへの苦手意識も少しだけマシになりました。構成自体はよくある各レイヤーについて解説したものではありますが、何と言っても、各レイヤーについて、実際のパケットの様子を、流れを丁寧に記述した図もあわせ、事細かに解説してくれている点がありがたいです。
各レイヤーのざっくりとした知識は前提として必要にはなりますが、繰り返し読むことで、ネットワークに関する知識を教科書的な段階から一歩先へ引き上げてくれるはずです。

また、本番サーバとしてDockerを利用する際には、HTTPS対応や、DNSなど、レイヤー1~3以外の知識も必要となるため、都度読み返すと、応用の際にもスムーズに学べるかもしれません。

※用語についていくのがしんどいと感じた場合は、「TCP/IPの絵本」から入るのもアリだと思います。

Linuxで動かしながら学ぶTCP/IPネットワーク入門

  • 学べること network namespaceの概要と、TCP/IPの各レイヤーの実際の通信の様子のイメージ

最近出た本ではありますが、読んでいてとても面白かったので、ここで紹介します。
Dockerではnetwork namespaceなるものを使うことで、仮想的なネットワークを設定することができる、といった感じの説明をよく見ますが、実際のところ、これだけでは、いまいちピンと来ません。

この書籍では、実際にnetwork namespaceで仮想的なネットワークを作成するだけにとどまらず、イーサネットや、IPでの通信を、ネットワークインタフェースを設定するところから丁寧に解説してくれています。

TCP/IPの各レイヤについて、network namespaceで通信に必要な設定・インタフェースを構築し、tcpdumpで実際の通信を確認しながら、通信ができるようになるまでを段階的に見ることができます。
Linuxの基礎を学び、上で挙げたネットワークの書籍に目を通したあとで取り組んでみると、ネットワークによってコンピュータ同士が通信できるようになるまでの流れがより深く学べることでしょう。

また、network namespaceで実際にインタフェースを設定することで、Dockerのネットワーク周りの理解も、更に進むかと思います。


(余談)
ネットワークの入門書と言えば、「ネットワークはなぜつながるのか」や「マスタリングTCP/IP 入門編」が定番として挙げられています。これらの書籍は確かに分かりやすく書かれていますが、ネットワークの知識がほとんど無い状態で挑むとかなり苦労することになります。(私はここから入ってめちゃくちゃ苦労しました)

まずは上記で挙げた入門書に目を通し、何らかの形で実際にネットワーク関連の知識が必要となった際、取り組んでみると、十分に楽しめるのではないかと思います。

Docker

Dockerの使い方を学ぶには、当然、Dockerそのものを勉強することも必要です。Dockerの入門情報は、Qiitaを始めとし、ネット上にたくさんの優れたものがあります。Docker 入門で検索し、良さそうだと思ったものをいくつか触っていけば、雰囲気はつかめるかと思います。
このとき、ただ読むだけでなく、実際に手を動かしながら、Dockerfileを書いてみたり、Docker Composeを使ってみたり、あれこれ試しながら、失敗したり、成功したり、といったことを経験するのが重要です。

最初のうちは各コマンドや、設定の記述が、なぜ必要なのかイメージが掴めず、苦労するかと思います。ですが、これまで挙げてきたもので基礎知識を身につけていれば、前提知識が足りず手も足も出ないということにはならないはずですので、少しずつでも理解を進められるはずです。

以下に、いくつか私が取り組んできたものを挙げますので、何から始めたら良いか迷っている場合は、練習問題がてら、触ってみるとよいかもしれません。

  • C言語の実行環境
  • Python + Pytestの実行環境
  • create-react-appを利用したReactの実行環境
  • デプロイされたWarファイルを実行するTomcat環境
  • Django + RDBMSそれぞれをコンテナ化し、DjangoアプリのデータをDBに保存可能とする環境

このとき、大抵のものは便利なイメージとして、既に公開されていたりしますが、最初のうちは、勉強も兼ねて、好きなLinuxディストリビューションをベースイメージとして構築してみると、理解が深まるかと思います。


ただ、やはり体系的に学ぶ上では、本を活用したいものです。
以下では、Dockerの入門書について、いくつか読んできた中で、特に良かったものを紹介します。

マンガでわかるDocker

  • 学べること: Dockerとはなんぞや~Dockerfileの基本あたりまで

全3冊ありますが、入門段階では、1巻・2巻だけでも十分だと思います。漫画形式でDockerの用語について解説されているので、「イメージ」や「コンテナ」などの言葉の意味は分かっていても、頭の中でイメージしづらい状態から脱するのに適しています。
ネット上の入門記事とあわせて読めば、最初の一歩として十分な理解が得られるでしょう。

Docker Deep Dive

  • 学べること: Dockerの基本的な概念の網羅・動作原理のさわり部分の理解

英語の書籍なので、一見難しそうに感じてしまいますが、難しい英単語や表現は使われていないので、英語がどうしようもないほど苦手でもなければ、ぜひ読んでみて頂きたいです。
Dockerの各種要素について、「概要」・「詳解」・「コマンド」形式で章立てて解説されており、ある章でいきなり難易度が跳ね上がることもないので、一歩ずつ確実に学ぶことができます。

ある程度手を動かした後に読んでみると、断片的に散らばっていた知識が明快な章立てにより、繋がることで、「Dockerなんも分からん」状態を抜け出せるはずです。
しっかりと内容を理解するには、Linuxやネットワークなど、幅広い知識が必要にはなりますが、これまで紹介したものを積み上げていけば、きっと立ち向かえることでしょう。

その他

Dockerそのものの理解とは少しずれますが、これもやって良かったな、と思ったことを以下にいくつか紹介します。

Vim

Vim Masterclass

  • 学べること: コンテナ内のファイル編集を手軽に行うための知識

コンテナに入ってちょっと設定ファイルなどを操作するとき、ホストからあれこれしたり、エディタの拡張機能などでも対応はできます。ですが、こういうときにサクッと操作できるツールがあればとても便利です。
そんなときに、Vimを勉強しておくと、コンテナの中でも快適に過ごせます。

Vimそのものについては、随所で熱く語られているため、詳細は割愛します。拡張機能ましましでカスタマイズするのでもなければ、上記のUdemyのコースで勉強すると、数時間で簡単な使い方を理解することができます。
英語ではありますが、字幕機能もありますし、何より練習問題がVimの基本操作を学ぶのに丁度いい形でつくられているので、Vimの良さを飽きることなく学べることでしょう。

Git

わかばちゃんと学ぶ Git使い方入門

エンジニアのためのGitの教科書[上級編] Git内部の仕組みを理解する

  • 学べること: Gitの基本コマンドとその仕組み

Gitそのものを知らなくてもDockerは理解できるかとは思います。しかし、Dockerで構築した環境で管理するアプリのソースコードは基本Gitで管理することとなるので、あわせて学んでおいて損はないです。

Gitはネット上はもちろんのこと、書籍もここに挙げた以外にも、素晴らしいものが充実しているので、迷子になるようなこともないかと思います。


まとめ

ちょっと整理するか、ぐらいの軽い気持ちで書き始めたら、思ったよりも長くなってしまいました。
Dockerを単なるツールとして使うためであれば、ここまでやらなくても、このコマンドを叩けばこうなる、と暗記し、用意されている素敵なイメージを使うことで、それなりのことはできてしまいます。

ですが、個人的には、多少遠回りにはなっても、基礎からしっかり学んで、なぜを追求していく方が良いと考えています。

これは優劣としてではなく、ただ単に、その方が楽しいからです。Dockerをきっかけに、ネットワークやLinuxに手を伸ばすようになり、1年ほど前よりもDockerはもちろんのこと、インフラ周り、Linuxのことが好きになりました。好きなものが増え、そこから更に深く学ぶと、知的好奇心が刺激され、それはそれは楽しいものです。

これ以上書くと脱線してしまうので、割愛しますが、この記事が少しでも楽しい学びの一助となれば幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む