20200517のdockerに関する記事は22件です。

Docker 環境で、Spring Boot アプリを、Visual Studio Code で開発する

まだまだ、仕事的にはJavaでの開発も考えないとな・・・ということで久しぶりに。
主力と思われるSpring Boot をちょっと試してみます。

まずはDocker環境

こちらを参照
VSCodeとDockerでSpring Boot + PostgreSQL開発環境を作る

$ docker-compose up -d
$ docker-compose ps -a
$ docker exec -it sb_db /bin/bash

# psql -d dev -U dev
dev=# select * from Names;
dev=# quit
# exit
$ docker-compose stop
$ docker-compose rm -f

「JavaコンテナからDBコンテナにアクセス」
からは若干環境を整えながらやる必要がありました。

まず、VSCodeで下記二つの拡張を追加
Remote - SSH
Remote - Containers

そうすると、REMOTE EXPLORER で、Containersが選択できるようになる。
選択すると、Dockerコンテナが一等表示される(こんなに作ってたんだ・・・)。

右クリックして、Attache to container で別ウインドウで開かれる。
そちらのウインドウで、SQLToolsをインストール。
こんなふうにDBに接続できるんですね。

さらに、Remote Development拡張をインストール。

そして、書かれているがままに進めていくと、無事プロジェクト作成成功。

デバッグ画面がちょっと異なっていてどまどいましたが、そのまま起動でOK。

Hello world!

続いて、DB接続用のファイルを追加。
追加していくと、勝手に最低限必要な記述が既に入っている。
今どきだな〜

しかし、ここで実行してみるとエラー発生。
まあ、ソース書いてる段階でエラーになってましたが。

javax.persistence
が解決されていません。

build.gradle
    compile 'org.springframework.boot:spring-boot-starter-data-jpa' // ← 追加(Spring Data JPA)

と言う形で、implementation を、compile に変更するとOK。
そういうものなのかな・・・(gradle初体験中)

これにより、無事データも表示されました。

テンプレートは当然のこと、コントローラを修正して保存すると、自動でビルドが動く感じですね。

これで基本の枠組みができました。

なお、この後、docker-compose.yml をちょっと修正。
今作業しているフォルダにJavaのソースも置くようにしたいと思い、volumes: の記述を追加しました。

docker-compose.yml
version: '3.2'
services:
    db:
        image: postgres:latest
        container_name: sb_db # "Spring Boot 用のDB" という意味の任意の名前
        restart: always
        # ports:
        #     - 5432:5432 # 今回はコンテナ同士でつなぐだけなのでコメントアウト
        environment:
            POSTGRES_USER: 'dev' # DBのユーザー名(=DB名)
            POSTGRES_PASSWORD: 'pass' # DBのパスワード
        volumes:
            - "./docker/db/initdb:/docker-entrypoint-initdb.d"
    java:
        image: openjdk:11
        container_name: sb
        restart: always
        ports:
            - 8080:8080 # ホストからデバッグできるようにポートフォーワード
        tty: true
        depends_on:
            - db
        volumes:
            - "./docker/java/src:/usr/local/src"

スクリーンショット 2020-05-14 8.58.02.png

画面デザイン

これでいわゆる普通のサーバアプリを開発する環境ができたわけですが、フロント側をどうするか。
templatesのHTMLにVueを組み込むと言うことを考えましたが、Vueを主として考えると、サーバ側はAPIの提供だけになる。
もちろんそれでも良いでのですが、今回の目的はJavaを主として開発する体制向けの調査なので、あまりVueの深いところに入っていくとちょっとずれてきてしまうので、その構成はやめました。

そう考えた時に、画面デザインは、Vuetifyとか、Bulmaとか、Element UIとかいいなと思っていたので、普通にSpring Boot で開発する場合のテンプレートのようなものも色々ないかなと思ったのですが、そ言う言う観点ではあまり見つからず。
やはり、主力は、Bootstrap か、ということで、Bootstrapテンプレートで探すと色々出てくる。
その中から組み込みやすそうな、Honoka にしてみました。
Honoka

一番シンプル?な、ダウンロード方式で行きます。
ダウンロードしたZipを展開するとhonokaフォルダができるので、それをそのまま、
・・・src/main/resources/static/honoka
に置きます。

テンプレートファイルに、cssとjsを組み込めば、反映されているようです。

index.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
  <head>
    <title>Demoアプリケーション</title>
    <link rel="stylesheet" type="text/css" href="honoka/css/bootstrap.min.css">
    <meta charset="utf-8" />
  </head>
  <body>
    <h1>Hello world!</h1>
    <p>Nameリスト</p>
    <div class="bs-component">
    <table class="table table-hover">
      <thead><tr><th>key</th><th>name</th></tr></thead>
      <tbody>
        <tr th:each="data : ${names}"><td th:text="${data.key}"></td><td th:text="${data.name}"></td></tr>
      </tbody>
    </table>
    </div>

    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="./honoka/js/bootstrap.min.js"></script>

    <script type="text/javascript">
      $('.bs-component [data-toggle="popover"]').popover();
      $('.bs-component [data-toggle="tooltip"]').tooltip();
    </script>

  </body>
</html>

ほのか.png

これで進めようと思ったのですが・・・

Azureへのデプロイ(失敗)

ここまでのところで、Azureにデプロイしようと考えました。
仕事的にはAzureを選択する可能性が一番高そうなので。

Azureの場合、App ServiceでさーばスペックをF1にすると、無料で使用可能です。

ところがこれがなかなか難しい。
基本的には、ほとんどが手順は、Maven前提に書かれています。
例えば、
https://www.eisbahn.jp/yoichiro/2019/01/azure-gradle-plugin.html
Azure App Service/Functions向けのGradleプラグイン
という情報もありますが、これもちょっと私では分かりにくかった。

まだまだ、Mavenが主力かと思い、いったん、
Spring Initializr: Generate a Gradle Project
じゃなくて
Spring Initializr: Generate a Maven Project
で再作成しました。
その際、このあ後で必要そうな気がして、MyBatis Frameworkも構成に含めました。

Mavenでのビルドは、こんな感じだそう。
./mvnw clean package
./mvnw spring-boot:run
これで確かに起動確認はできているが、DB接続はできていない模様(DBからのリストが表示されていない)。

けど、とりあえず動いているし、ということで、デプロイしてみることに。

Azure CLI のインストール
https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli?view=azure-cli-latest

Debian または Ubuntu での apt を使用したインストール
(apt での Azure CLI のインストール)
https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli-apt?view=azure-cli-latest

# curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash
bash: sudo: command not found

まじか

# apt-get update
# apt-get install -y sudo

これで、cliからazにログイン。

で、

./mvnw com.microsoft.azure:azure-webapp-maven-plugin:1.8.0:config

とすると、いろいろオプションを聞かれて、いろいろ進んで、

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  06:30 min
[INFO] Finished at: 2020-05-14T23:59:23Z
[INFO] ------------------------------------------------------------------------

# ./mvnw  azure-webapp:deploy

[INFO] Successfully deployed the artifact to https://demo-1589500547098.azurewebsites.net

とはなる。
しかし、エラー画面。詳細を見ると、

org.postgresql.util.PSQLException: The connection attempt failed.

まあ、そうだよね、DB立ててないからね。
ちなみに、上記のようにやって、App Serviceを自動で作成するようにすると、自動で作られたのは、Premium V2。
危険!!
プラン変更
https://docs.microsoft.com/ja-jp/azure/app-service/app-service-plan-manage
けど失敗してしまったので、いったん削除(リソースグループまで削除しないとエラーになる)。

で、この後、いったんDB接続しないように修正して試したりしていたのですが、なかなかうまくいかない。そして、そもそも、結局Azureだと、DBまで無料で試すことはできない・・・。
ということで断念することにしました。

Heroku へのデプロイ

そういうわけで、Herokuへデプロイすることにしました。

https://himeji-cs.jp/blog2/blog/2019/08/hello-heroku-with-springboot.html
こちらの「ローカルでビルドした jar をデプロイする」を大いに参考にさせていただきました。

heroku-cliを入れて、javaプラグインを入れて、system.properties を作成して、Procfile を作成、という流れになります。

heroku deploy:jar で最初動いてくれませんでしたが、git管理フォルダでないと動かないようです。
今回の環境の場合、この作業をしているフォルダの配下に、docker/java/src/demo という階層構造を作っており、アプリケーションとしてはdemoが起点となるため、ここがgit管理フォルダになっていないといけないということです。これに対して、現状は、作業フォルダがgit管理フォルダです。
こんなことやって良いか分からなかったですが、demoフォルダで改めてgit init しました。結果的にはこれでOKでした。

DBに接続しない状態でのデプロイができたので、続いて、DB環境を作って、接続します。

こちらを参考にしました。
https://mhaya18.hatenablog.com/entry/2018/11/25/151403

https://devcenter.heroku.com/articles/getting-started-with-gradle-on-heroku#use-a-database

ここはさほど悩まずにすんなりいきました。

ダッシュボードテンプレート

さて、上記でクライアント側Bootstrapテンプレートを導入しましたが、改めてやろうとしていることを考えるとダッシュボード機能も欲しいぞと。

これもいろいろ悩んだ挙句、Charismaにしました。

決め手は、導入の手順がファイルコピーだけで良いということ。
これで見た目が整うことは分かりました。

ただ、複数ページでヘッダ等を共有する仕組みになっていない。
すなわち、一つ修正したら全部修正が必要。
むむ。

ここで、Thymeleaf 登場。これも、名前は聞いていたものの、初使用。
Thymeleafでヘッダーフッターを共通化する方法

こちらを見ながら、公式も見ることで、Thymeleafの基本はよく分かりました。
ただ、肝心の,
body部に関して、その中に、サイドメニューがあり、フッタがあり、そこまではよいとして、さらに、body内で様々なscriptタグを使っている場合の上手いやり方が見えませんでした。

と、今度は、こんなページを発見。
https://macchinetta.github.io/server-guideline-thymeleaf/current/ja/ArchitectureInDetail/WebApplicationDetail/TemplateLayout.html

これはよくできていると思ったのですが、このページはなんなんだろうと調べてみると、Macchinettaという、NTTのフレームワーク。

ん?NTTグループといえば、TERASOLUNAでは?と思ったところ、こちらのMacchinettaがリリースされましたによると、テラそるなを包含したフレームワーク?
とりあえず、素性も悪くないということで、ありがたく参照させていただきます。

で、ここでいったんherokuに最新をデプロイしておこうと思ったらトラブル。
heroku deploy をしようとすると、jarがないと言われる。
mvnw clean package をしようとすると、targetフォルダを削除できないと言われる。
targetフォルダを削除すると、すぐ勝手に作られる。
・・・悩みました。

現在、VSCodeのRemote Containers拡張から画面を開いている状態ですが、これを閉じると、自動で作成されなくなる。(ここにたどり着くまでに、コンテナ再起動等いろいろ試しましたが・・・)

ではということで、Remote Containers拡張を使用せず、

docker exec -it sb /bin/bash

でコンテナ内に入って、mvnw clean package を実行しました。
これでjarが作られてしまえば、もう一度Remote Containers拡張で接続しても大丈夫。
無事デプロイしました。

データ取得

最後にデータ取得。いったんここで最後にします。
DB接続の仕組みは動いているものの、既存のGoogleスプレッドシートのデータを使用するため、外部API呼び出しを、クライアント側からやれば良いのではと思いつき。

であれば、Vueもやっておきたい、ということで、こちらを参考にさせていただきます。
CDN版Vue.js + axios でさくっとAjaxしてみる

配置等はわざと変更してみましたが、基本的にはそのまま動作します。
感動です。

なお、Google スプレッドシート のデータ公開の方法は、先日書いたこちらを参照。
RPGツクール 外部API連携

これの「コード.gs」の内容をそのまま貼り付けて、公開すれば、そのURLでデータを取得できます。

訳わからないでしょうが、いったん公開。

https://jq-spring-boot-first.herokuapp.com/

今後は、コンテンツを整えながら、データ検索等の仕組みを作っていきます。

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

ぼく「Djangoのリモートデバッグも出来ないエディターなんて…」VSCode「それ、できるで。」~docker-compose編~

はじめに

VSCode「そう。Remote Developmentならね。」

ぼく「なん…やて…」

目次

前提条件

VSCode「docker-composeでのデバッグをやっていくから、まずは下のわかりやすい記事を参考に環境構築を行ってな。」

ぼく「手前味噌やな。」

VSCode「フォルダ構成は以下の通りになっているはずやで。」

tree
containers
├── django
│   ├── Dockerfile
│   ├── Pipfile
│   ├── Pipfile.lock
│   ├── config
│   │   ├── __init__.py
│   │   ├── asgi.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── db.sqlite3
│   ├── entrypoint.sh
│   ├── manage.py
│   └── static
├── docker-compose.yml
├── nginx
│   ├── Dockerfile
│   └── nginx.conf
└── postgres
    ├── Dockerfile
    └── sql
        └── init.sql

VSCode「ほんだら、containersディレクトリをワイ(VSCode)開いてな。」

ぼく「あいよ。」

Remote Developmentのインストール

VSCode「Remote Developmentをインストールしてな。左下にこんな感じの青いマークが出てればインストール完了や」

image1.png

設定ファイルの追加

VSCode「次にデバッグ用の設定ファイルを追加していくで。」

VSCode「出てきた青いアイコンをクリックしてな。」

ぼく「あいよ。」

VSCode「したら上にメニューが出てくるやろ?そん中からRemote-Containers: Add Development Container configuration Files...を選択してな。」

image2.png

VSCode「そのあとFrom 'docker-compose.yml'を選択や。」

image3.png

  • デバックしたいサービスを選択(今回はDjango)を選択 image4.png

VSCode「するとプロジェクトのルートに.devcontainerディレクトリと、その中にdevcontainer.json及びdocker-compose.ymlが出来上がるから、devcontainer.jsonを以下のように書き換えてな!」

VSCode「この辺は実務で使ったりする場合は任意の環境に置き換えて使ってな!」

ぼく「設定ファイル周りはようハマるからきーつけなあかんな。」

devcontainer.json
{
  // 任意の名前を入力
  "name": "djnago containers",
  // Remoteでログインしたいコンテナを作成するためのdocker-composeファイルを指定してください。
  "dockerComposeFile": "docker-compose-debug.yml",
  // 起動したいサービスを選択
  "service": "django",
  // コンテナに入ったときに最初にここで指定したものがカレントディレクトリになります
  "workspaceFolder": "/usr/src/app/",
  // シェルを選択
  "settings": {
    "terminal.integrated.shell.linux": "/bin/bash"
  },
  // vscode拡張機能を選択
  "extensions": ["ms-azuretools.vscode-docker", "ms-python.python"],
  // vscodeを閉じた時のコンテナの挙動を設定
  // noneでコンテナの起動を継続する
  "shutdownAction": "none"
}

VSCode「次にデバッグ用のymlに書き換えていくで!.devcontainerディレクトリ内の自動生成されたdocker-compose.ymldocker-compose-debug.ymlとかに修正し、既存のdocker-compose.ymlの内容をコピーしてな。」

VSCode「今の段階ではサービスがdjangopostgresnginxの3つあるけど、デバッグ時にいちいちnginxから配信しなくてええから、以下のように修正してな。これも環境に合わせて任意に変えてな。」

  • 修正点
    • nginxサービスを削除
    • djangoサービスにデバッグ用のポート8888を開放
    • Dockerfileやマウントディレクトリなどのパスを修正
docker-compose-debug.yml
version: '3.7'
services:
    django:
        container_name: django
        build: ../django
        command: python3 manage.py runserver 0.0.0.0:8000
        volumes:
            - ../django:/usr/src/app/
        ports:
            - 8000:8000
            # デバッグ用にポートを追加
            - 8888:8888
        env_file:
            - ../django/.env
        depends_on:
            - postgres

    postgres:
        container_name: postgres
        build: ../postgres
        volumes:
            - sample_postgis_data:/var/lib/postgresql/data
            - ../postgres/sql:/docker-entrypoint-initdb.d
        env_file: ../postgres/.env_db
        ports:
            - 5433:5432

volumes:
    sample_postgis_data:

リモートデバッグの開始

VSCode「今はこんな感じのディレクトリになっとるはずやな。」

ぼく「せやな。」

tree
containers
├── .devcontainer
│   ├── devcontainer.json
│   └── docker-compose-debug.yml
├── django
│   ├── .env
│   ├── Dockerfile
│   ├── Pipfile
│   ├── Pipfile.lock
│   ├── config
│   │   ├── __init__.py
│   │   ├── asgi.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── db.sqlite3
│   ├── entrypoint.sh
│   ├── manage.py
│   └── static
├── docker-compose.yml
├── nginx
│   ├── Dockerfile
│   └── nginx.conf
└── postgres
    ├── .env_db
    ├── Dockerfile
    └── sql
        └── init.sql

VSCode「いよいよデバッグしていくわけやけど、すでにdocker-compose.ymlでコンテナを立ち上げている場合は一旦停止させておいてな。デバッグ時にコンテナを立て直すんやけど、元々のymlファイルが同じものを使っているから名前が競合してうまく立ち上がらんくなるで。」

VSCode「停止を確認したら下の青いアイコンを押して、次はRemote-Containers: Open Folder in Containers...をクリックして、.devcontainerが存在するディレクトリ(今回の例ではcontainers)を選択してな。」

image5.png

VSCode「ちなみにすでにコンテナが立ち上がっている場合はRemote-Containers: Attach to Running Containers...を選択するとすでに起動中のコンテナにログインできるんやけど、devcontainer.jsonで作成した設定が反映されず、拡張機能がインストールされないから注意な」

ぼく「これもハマりポイントやな。メモメモ…」

VSCode「ディレクトリを選択すると新しいウィンドウが開いて、以下のような表示が画面右下に出るで。コンテナ起動中やからしばらく待ってな」

ぼく「結構長いで。気長にいこうな。せっかちは嫌われるで。」

VSCode「ちなみに青文字のStarting with Dev Containerをクリックするとコンテナ起動に必要なプロセスのログがリアルタイムでみれるで。エラーが起きたら停止してまうねんけど、このログでどこが悪いのか見れるで。」

VSCode「まぁ、大抵はパス間違いか、名前の競合やろけどな。」

image6.png

VSCode「無事立ち上がったら、コンテナ内のディレクトリが表示されて、シェルも指定のディレクトリをカレントディレクトリとして開いており、起動したコンテナにアタッチされたことが確認できるで。」

image7.png

VSCode「拡張機能もインストール済みや。」

ぼく「そもそも、拡張機能はインストールしたいものをdevcontainer.jsonで明示的に書いてあげないとダメなんやな…」

image8.png

デバッグの開始

VSCode「実行とデバッグのアイコンをクリックし、launch.jsonファイルを作成しますをクリックして…」

image9.png

VSCode「その後、Docker Debug ins Containerをクリックし…」

image10.png

VSCode「んでlaunch.jsonの編集画面が開くので以下のように編集して完成や!」

launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            // 表示名
            "name": "django container",
            // 言語
            "type": "python",
            // デバッグ時の挙動。実行の他にもある
            "request": "launch",
            // 動作させるファイルへのパス
            "program": "${workspaceFolder}/manage.py",
            // デバッグで使用するターミナルを選択。VSCode外のターミナルを起動することもできる
            "console": "integratedTerminal",
            // プログラム実行時の引数
            "args": [
                "runserver",
                "--noreload",
                "0.0.0.0:8888"
            ],
            "django": true
        }
    ]
}

VSCode「最後にプログラムを実行するために、画面左下からインタープリタを選択するで(今回の例であればpython3.8を選択)」

image11.png

VSCode「一通りの設定が終わると、実行とデバッグの項目が以下のようになり、再生ボタンのような緑色の三角アイコンをクリックすることで、指定した0.0.0.0:8888でデバッグサーバーが立ち上がるんや。」

image12.png

VSCode「ボタンを押した後にブラウザからlocalhost:8888に接続するといつもの画面が見れるようになっているはずや」

ぼく「ほんまや。」

image13.png

VSCode「あとはデバッグを行いたい箇所にブレークポイントを設定してブラウザなどからブレークポイントを設置した関数が実行されるようなURLにアクセスすると、VScode上でリクエストの内容がみれたり、変数が確認できたりするで!」

VSCode「VSCode デバッグとかでググったら細かいやり方たくさん出てくるから調べてみてな!」

ぼく「VSCode神やな!ほなさいなら。」

お し ま い

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

ぼく「コンテナのリモートデバッグも出来ないエディターなんて…」VSCode「それ、できるで。」

はじめに

VSCode「そう。Remote Developmentならね。」

ぼく「なん…やて…」

目次

前提条件

VSCode「docker-composeでのデバッグをやっていくから、まずは下のわかりやすい記事を参考に環境構築を行ってな。」

ぼく「手前味噌やな。」

VSCode「フォルダ構成は以下の通りになっているはずやで。」

tree
containers
├── django
│   ├── Dockerfile
│   ├── Pipfile
│   ├── Pipfile.lock
│   ├── config
│   │   ├── __init__.py
│   │   ├── asgi.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── db.sqlite3
│   ├── entrypoint.sh
│   ├── manage.py
│   └── static
├── docker-compose.yml
├── nginx
│   ├── Dockerfile
│   └── nginx.conf
└── postgres
    ├── Dockerfile
    └── sql
        └── init.sql

VSCode「ほんだら、containersディレクトリをワイ(VSCode)開いてな。」

ぼく「あいよ。」

Remote Developmentのインストール

VSCode「Remote Developmentをインストールしてな。左下にこんな感じの青いマークが出てればインストール完了や」

image1.png

設定ファイルの追加

VSCode「次にデバッグ用の設定ファイルを追加していくで。」

VSCode「出てきた青いアイコンをクリックしてな。」

ぼく「あいよ。」

VSCode「したら上にメニューが出てくるやろ?そん中からRemote-Containers: Add Development Container configuration Files...を選択してな。」

image2.png

VSCode「そのあとFrom 'docker-compose.yml'を選択や。」

image3.png

  • デバックしたいサービスを選択(今回はDjango)を選択 image4.png

VSCode「するとプロジェクトのルートに.devcontainerディレクトリと、その中にdevcontainer.json及びdocker-compose.ymlが出来上がるから、devcontainer.jsonを以下のように書き換えてな!」

VSCode「この辺は実務で使ったりする場合は任意の環境に置き換えて使ってな!」

ぼく「設定ファイル周りはようハマるからきーつけなあかんな。」

devcontainer.json
{
  // 任意の名前を入力
  "name": "djnago containers",
  // Remoteでログインしたいコンテナを作成するためのdocker-composeファイルを指定してください。
  "dockerComposeFile": "docker-compose-debug.yml",
  // 起動したいサービスを選択
  "service": "django",
  // コンテナに入ったときに最初にここで指定したものがカレントディレクトリになります
  "workspaceFolder": "/usr/src/app/",
  // シェルを選択
  "settings": {
    "terminal.integrated.shell.linux": "/bin/bash"
  },
  // vscode拡張機能を選択
  "extensions": ["ms-azuretools.vscode-docker", "ms-python.python"],
  // vscodeを閉じた時のコンテナの挙動を設定
  // noneでコンテナの起動を継続する
  "shutdownAction": "none"
}

VSCode「次にデバッグ用のymlに書き換えていくで!.devcontainerディレクトリ内の自動生成されたdocker-compose.ymldocker-compose-debug.ymlとかに修正し、既存のdocker-compose.ymlの内容をコピーしてな。」

VSCode「今の段階ではサービスがdjangopostgresnginxの3つあるけど、デバッグ時にいちいちnginxから配信しなくてええから、以下のように修正してな。これも環境に合わせて任意に変えてな。」

  • 修正点
    • nginxサービスを削除
    • djangoサービスにデバッグ用のポート8888を開放
    • Dockerfileやマウントディレクトリなどのパスを修正
docker-compose-debug.yml
version: '3.7'
services:
    django:
        container_name: django
        build: ../django
        command: python3 manage.py runserver 0.0.0.0:8000
        volumes:
            - ../django:/usr/src/app/
        ports:
            - 8000:8000
            # デバッグ用にポートを追加
            - 8888:8888
        env_file:
            - ../django/.env
        depends_on:
            - postgres

    postgres:
        container_name: postgres
        build: ../postgres
        volumes:
            - sample_postgis_data:/var/lib/postgresql/data
            - ../postgres/sql:/docker-entrypoint-initdb.d
        env_file: ../postgres/.env_db
        ports:
            - 5433:5432

volumes:
    sample_postgis_data:

リモートデバッグの開始

VSCode「今はこんな感じのディレクトリになっとるはずやな。」

ぼく「せやな。」

tree
containers
├── .devcontainer
│   ├── devcontainer.json
│   └── docker-compose-debug.yml
├── django
│   ├── .env
│   ├── Dockerfile
│   ├── Pipfile
│   ├── Pipfile.lock
│   ├── config
│   │   ├── __init__.py
│   │   ├── asgi.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── db.sqlite3
│   ├── entrypoint.sh
│   ├── manage.py
│   └── static
├── docker-compose.yml
├── nginx
│   ├── Dockerfile
│   └── nginx.conf
└── postgres
    ├── .env_db
    ├── Dockerfile
    └── sql
        └── init.sql

VSCode「いよいよデバッグしていくわけやけど、すでにdocker-compose.ymlでコンテナを立ち上げている場合は一旦停止させておいてな。デバッグ時にコンテナを立て直すんやけど、元々のymlファイルが同じものを使っているから名前が競合してうまく立ち上がらんくなるで。」

VSCode「停止を確認したら下の青いアイコンを押して、次はRemote-Containers: Open Folder in Containers...をクリックして、.devcontainerが存在するディレクトリ(今回の例ではcontainers)を選択してな。」

image5.png

VSCode「ちなみにすでにコンテナが立ち上がっている場合はRemote-Containers: Attach to Running Containers...を選択するとすでに起動中のコンテナにログインできるんやけど、devcontainer.jsonで作成した設定が反映されず、拡張機能がインストールされないから注意な」

ぼく「これもハマりポイントやな。メモメモ…」

VSCode「ディレクトリを選択すると新しいウィンドウが開いて、以下のような表示が画面右下に出るで。コンテナ起動中やからしばらく待ってな」

ぼく「結構長いで。気長にいこうな。せっかちは嫌われるで。」

VSCode「ちなみに青文字のStarting with Dev Containerをクリックするとコンテナ起動に必要なプロセスのログがリアルタイムでみれるで。エラーが起きたら停止してまうねんけど、このログでどこが悪いのか見れるで。」

VSCode「まぁ、大抵はパス間違いか、名前の競合やろけどな。」

image6.png

VSCode「無事立ち上がったら、コンテナ内のディレクトリが表示されて、シェルも指定のディレクトリをカレントディレクトリとして開いており、起動したコンテナにアタッチされたことが確認できるで。」

image7.png

VSCode「拡張機能もインストール済みや。」

ぼく「そもそも、拡張機能はインストールしたいものをdevcontainer.jsonで明示的に書いてあげないとダメなんやな…」

image8.png

デバッグの開始

VSCode「実行とデバッグのアイコンをクリックし、launch.jsonファイルを作成しますをクリックして…」

image9.png

VSCode「その後、Docker Debug ins Containerをクリックし…」

image10.png

VSCode「んでlaunch.jsonの編集画面が開くので以下のように編集して完成や!」

launch.json
{
    "version": "0.2.0",
    "configurations": [
        {
            // 表示名
            "name": "django container",
            // 言語
            "type": "python",
            // デバッグ時の挙動。実行の他にもある
            "request": "launch",
            // 動作させるファイルへのパス
            "program": "${workspaceFolder}/manage.py",
            // デバッグで使用するターミナルを選択。VSCode外のターミナルを起動することもできる
            "console": "integratedTerminal",
            // プログラム実行時の引数
            "args": [
                "runserver",
                "--noreload",
                "0.0.0.0:8888"
            ],
            "django": true
        }
    ]
}

VSCode「最後にプログラムを実行するために、画面左下からインタープリタを選択するで(今回の例であればpython3.8を選択)」

image11.png

VSCode「一通りの設定が終わると、実行とデバッグの項目が以下のようになり、再生ボタンのような緑色の三角アイコンをクリックすることで、指定した0.0.0.0:8888でデバッグサーバーが立ち上がるんや。」

image12.png

VSCode「ボタンを押した後にブラウザからlocalhost:8888に接続するといつもの画面が見れるようになっているはずや」

ぼく「ほんまや。」

image13.png

VSCode「あとはデバッグを行いたい箇所にブレークポイントを設定してブラウザなどからブレークポイントを設置した関数が実行されるようなURLにアクセスすると、VScode上でリクエストの内容がみれたり、変数が確認できたりするで!」

VSCode「VSCode デバッグとかでググったら細かいやり方たくさん出てくるから調べてみてな!」

ぼく「VSCode神やな!ほなさいなら。」

お し ま い

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

Dockerfileのdebug

Dockerfile の debug

# docker startが終わったcontainerを確認
$ docker ps -a

# 対象のCONTAINER IDをコピーする

# containerを一時的にimage化する
$ docker commit <container-id> builddebug

# image化したdockerをdocker runする
$ docker run --rm -it builddebug /bin/bash

# これでdocker buildで失敗した時点のコンテナに入る事ができる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】.env.testingの使用方法と注意点

LaravelでPHPUnitを使うときにテスト用の`.env`を設定するのにハマったので記事にしました。

環境

Docker 19.03.8
PHP 7.3.16
Laravel 6.18.3

.env.testingの設定方法

本番DBを汚さないようにPHPUnitを実行する時のみテスト用のDBを使うようなことはよくあると思います。

その方法の一つとして.env.testingを作成し、phpunitにその設定値を読み込ませるやり方があります。

.env.exampleをコピーして.env.testingを作成し、以下の箇所を変更します。

env.testing
APP_ENV=testing // testingに変更
APP_KEY= // 空にしておく

// 接続したいDBの情報を設定する
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=test_database
DB_USERNAME=root
DB_PASSWORD=

そうしたらphpunit.xmlを開き、APP_ENVの値をtestingに変更します。

phpunit.xml
<php>
    <env name="APP_ENV" value="testing" force="true"/>
    <env name="DB_CONNECTION" value="mysql"/>
    <env name="BCRYPT_ROUNDS" value="4"/>
    <env name="CACHE_DRIVER" value="array"/>
    <env name="MAIL_DRIVER" value="array"/>
    <env name="QUEUE_CONNECTION" value="sync"/>
    <env name="SESSION_DRIVER" value="array"/>
</php>

最後に.env.testingに新規にアプリケーションキーを設定したら完了です。
これをしないと.envAPP_KEYを参照しに行ってしまい、本番用のDBのデータが全部飛ぶので注意しましょう。

php artisan key:generate --env=testing

ハマったポイント

docker-compose.ymlなどで環境変数にAPP_ENVDB_DATABASEなどの設定をしている場合、注意しなくてはいけない点があります。
phpunit.xmlで環境変数を上書きする際に、デフォルトだと<server>タグになっていますが、これを<env>タグに変更する必要があります。

phpunit.xml
<php>
    <server name="APP_ENV" value="testing" force="true"/>
    <server name="DB_CONNECTION" value="mysql"/>
    ...
</php>
phpunit.xml
<php>
    <env name="APP_ENV" value="testing" force="true"/>
    <env name="DB_CONNECTION" value="mysql"/>
    ...
</php>

<server>タグと<env>タグは以下のような違いになっています。

$_SERVER['APP_ENV'] = 'testing'; // <server>
$_ENV['APP_ENV'] = 'testing'; // <env>

今回はdocker-compose.ymlで環境変数としてAPP_ENVなどを定義していたので、さらにそれを上書きする必要がありました。

参考文献

Laravel 7.x テスト: テストの準備
Laravel × Docker でテスト用のデータベースコンテナを使う

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

github actionsを開発して公開するまで(Docker編)

はじめに

Github Actions便利ですよね.毎月2000分までタダで使えるので,個人プロジェクトはほぼこれでまかなえてしまいます.Docker,もしくはJavaScriptで開発できるので,バックエンドの方もフロントの方も触りやすそうです.

すでに公式日本語ドキュメントがあるので,最新情報はこちらを確認してください.
個人的に手順全体の概要があったほうがわかりやすいと思い,この記事を書いています.
action.ymlの役割とAction自体を検証するCIの作成方法は役立つと思います.
その他の詳細部分も書きましたが,個別のAction実装作業には役立たないので読まなくても大丈夫だと思います.

この記事の前提

  • Dockerを利用して開発する前提です.JavaScriptでの開発は扱いません.
  • Dockerにある程度詳しいことを前提としています.

開発に至った背景

  • CI上でElasticSearchを起動したかったが,公式のActionがまだ利用したいバージョンに対応していなかった
  • 利用しているプラグインをインストールした状態でテストしたかったが,こちらも公式が未対応だった
  • なので,上記2点を改善したアクションを自分で開発することにした.

手順の概要

  1. 新しいrepositoryを作る
  2. action.ymlを作る(これから作るActionがどんな引数を受け取るのか定義する)
  3. Dockerfileを作る
  4. コンテナ起動時に実行されるスクリプトを作る
  5. 今回開発したAction自体をテストするCIワークフローを定義する
  6. マーケットプレイスに公開する

詳細

新しいrepositoryを作る

  • 新しいrepositoryを作ります(対象読者には説明不要と思われるので省略)
  • READMEを追加せよと公式にはありますが,なくても動きます.もちろん公開するわけなので,あったほうがベター.英語だとよりベターでしょう.
  • 下記は一例です
README.md
# elasticsearch-github-actions

setup elasticsearch in your github actions' workflow

## Usage
steps:
- name: Configure sysctl limits
  run: |
    sudo swapoff -a
    sudo sysctl -w vm.swappiness=1
    sudo sysctl -w fs.file-max=262144
    sudo sysctl -w vm.max_map_count=262144

- uses: miyataka/elasticsearch-github-actions@1
  with:
    stack-version: '7.6.2'
    plugins: 'analysis-kuromoji analysis-icu'

action.ymlを作る(これから作るActionがどんな引数を受け取るのか定義する)

  • 今回開発したものを引用します
action.yml
name: 'Run Elasticsearch with Plugins'         # actionの名前,マケプレで表示される.
description: 'Elasticsearch with Plugins'      # actionの説明,マケプレで表示される.
author: 'miyataka'                             # 自分のgithubIDなど

branding:                                      # マケプレのアイコンを設定する
  icon: 'database'
  color: 'red'

inputs:                                        # Actionを実際にCIで使うときに,渡してほしいパラメータを定義する
  stack-version:
    description: 'The version of Elasticsearch'
    required: true
  plugins:
    description: 'Elasticsearch plugin strings'
    required: false
    default: ''

runs:
  using: 'docker'
  image: 'Dockerfile'
  env:
    STACK_VERSION: ${{ inputs.stack-version }} # inputでもらったパラメータを環境変数に設定してコンテナにわたす
    PLUGINS: ${{ inputs.plugins }}

Dockerfileを作る

  • やっていることはシンプルです.entrypoint.shをイメージに追加しているだけ.
  • 今回諸事情でdocker in dockerをやるので,ベースイメージは内部でdockerコマンドを使えるdocker:stableです
FROM docker:stable
RUN apk add --update bash
COPY entrypoint.sh /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

コンテナ起動時に実行されるスクリプトを作る

  • さきほど登場したentrypoint.shを実装します
  • hello worldでもなんでもいいのですが,説明の都合上今回開発したものを引用します
#!/bin/bash

set -euxo pipefail

# 必須にした引数が存在するかチェック
if [[ -z $STACK_VERSION ]]; then
  echo -e "\033[31;1mERROR:\033[0m Required environment variable [STACK_VERSION] not set\033[0m"
  exit 1
fi

docker network create elastic

PLUGINS_STR=`echo ${PLUGINS} | sed -e 's/\n/ /g'` # 引数に含まれている改行文字を置換
MAJOR_VERSION=`echo ${STACK_VERSION} | cut -c 1`  # メジャーバージョンを取得

PLUGIN_INSTALL_CMD=""

# pluginsを複数インストールするケースがあるのでfor文でコマンドを組み立てる
if [ "x${PLUGINS_STR}" != "x" ]; then
    ARRAY=(${PLUGINS_STR})
    for i in "${ARRAY[@]}"
    do
        PLUGIN_INSTALL_CMD+="elasticsearch-plugin install --batch ${i} && "
    done
fi

# single node only
if [ "x${MAJOR_VERSION}" == 'x6' ]; then # メジャーバージョンによって起動オプションを分岐する.
  docker run \
    --rm \
    --env "node.name=es1" \
    --env "cluster.name=docker-elasticsearch" \
    --env "cluster.routing.allocation.disk.threshold_enabled=false" \
    --env "bootstrap.memory_lock=true" \
    --env "ES_JAVA_OPTS=-Xms1g -Xmx1g" \
    --env "xpack.security.enabled=false" \
    --env "xpack.license.self_generated.type=basic" \
    --ulimit nofile=65536:65536 \
    --ulimit memlock=-1:-1 \
    --publish "9200:9200" \
    --detach \
    --network=elastic \
    --name="es1" \
    --entrypoint="" \
    docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} \
    /bin/sh -vc "${PLUGIN_INSTALL_CMD} /usr/local/bin/docker-entrypoint.sh"
elif [ "x${MAJOR_VERSION}" == 'x7' ]; then
  docker run \
    --rm \
    --env "node.name=es1" \
    --env "cluster.name=docker-elasticsearch" \
    --env "cluster.initial_master_nodes=es1" \
    --env "discovery.seed_hosts=es1" \
    --env "cluster.routing.allocation.disk.threshold_enabled=false" \
    --env "bootstrap.memory_lock=true" \
    --env "ES_JAVA_OPTS=-Xms1g -Xmx1g" \
    --env "xpack.security.enabled=false" \
    --env "xpack.license.self_generated.type=basic" \
    --ulimit nofile=65536:65536 \
    --ulimit memlock=-1:-1 \
    --publish "9200:9200" \
    --detach \
    --network=elastic \
    --name="es1" \
    --entrypoint="" \
    docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} \
    /bin/sh -vc "${PLUGIN_INSTALL_CMD} /usr/local/bin/docker-entrypoint.sh"
fi

# 上記で起動したコンテナに対して,curlで死活確認するコンテナを立ち上げる
docker run \
  --network elastic \
  --rm \
  appropriate/curl \
  --max-time 120 \
  --retry 120 \
  --retry-delay 1 \
  --retry-connrefused \
  --show-error \
  --silent \
  http://es1:9200

sleep 10

echo "Elasticsearch up and running"

今回開発したAction自体をテストするCIワークフローを定義する

  • すでにActionを使った事がある場合にはご存知でしょうが,.github/workflows/*.ymlを配置するとCIを実行してくれますね.
  • 今回開発したAction自体も思ったとおりに動くか検証するためのCIを作りました
name: Elasticsearch Github Action

on: [push]

jobs:
  run-action:
    name: Start Elasticsearch
    runs-on: ubuntu-latest
    strategy:
      matrix:
        elasticsearch: ["6.4.3", "7.6.2"]
    steps:
      - name: Checkout
        uses: actions/checkout@v1

      - name: Configure sysctl limits
        run: |
          sudo swapoff -a
          sudo sysctl -w vm.swappiness=1
          sudo sysctl -w fs.file-max=262144
          sudo sysctl -w vm.max_map_count=262144

      - name: Start Elasticsearch                     # 重要なのはこの部分
        uses: ./
        with:
          stack-version: ${{ matrix.elasticsearch }}
          plugins: |
            analysis-kuromoji
            analysis-icu

      - name: Elasticsearch is reachable
        run: |
          curl --verbose --show-error http://localhost:9200

マーケットプレイスに公開する

  • 動作確認もできたら,あとは公開するだけです.
  • ここまでの手順を踏んでいれば,以下のような表示がされているはずです. publish-github-action-to-markeplace-button.png
  • このボタンを押して,指示に従い公開しましょう.
  • ここは公式docをみたほうがいいですね

参考と補足

最後に

すでにたくさんActionsが公開されているのですが,まだまだかゆいところに手が届かない感じのものも多いです.
OSS開発するにはまだまだブルーオーシャンです.皆で開発&公開してよりよい開発効率を目指しましょう!

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

GitHub Actionsを開発して公開するまで(Docker編)

はじめに

Github Actions便利ですよね.毎月2000分までタダで使えるので,個人プロジェクトはほぼこれでまかなえてしまいます.Docker,もしくはJavaScriptで開発できるので,バックエンドの方もフロントの方も触りやすそうです.

すでに公式日本語ドキュメントがあるので,最新情報はこちらを確認してください.
個人的に手順全体の概要があったほうがわかりやすいと思い,この記事を書いています.
action.ymlの役割とAction自体を検証するCIの作成方法は役立つと思います.
その他の詳細部分も書きましたが,個別のAction実装作業には役立たないので読まなくても大丈夫だと思います.

この記事の前提

  • Dockerを利用して開発する前提です.JavaScriptでの開発は扱いません.
  • Dockerにある程度詳しいことを前提としています.

開発に至った背景

  • CI上でElasticSearchを起動したかったが,公式のActionがまだ利用したいバージョンに対応していなかった
  • 利用しているプラグインをインストールした状態でテストしたかったが,こちらも公式が未対応だった
  • なので,上記2点を改善したアクションを自分で開発することにした.

手順の概要

  1. 新しいrepositoryを作る
  2. action.ymlを作る(これから作るActionがどんな引数を受け取るのか定義する)
  3. Dockerfileを作る
  4. コンテナ起動時に実行されるスクリプトを作る
  5. 今回開発したAction自体をテストするCIワークフローを定義する
  6. マーケットプレイスに公開する

詳細

新しいrepositoryを作る

  • 新しいrepositoryを作ります(対象読者には説明不要と思われるので省略)
  • READMEを追加せよと公式にはありますが,なくても動きます.もちろん公開するわけなので,あったほうがベター.英語だとよりベターでしょう.
  • 下記は一例です
README.md
# elasticsearch-github-actions

setup elasticsearch in your github actions' workflow

## Usage
steps:
- name: Configure sysctl limits
  run: |
    sudo swapoff -a
    sudo sysctl -w vm.swappiness=1
    sudo sysctl -w fs.file-max=262144
    sudo sysctl -w vm.max_map_count=262144

- uses: miyataka/elasticsearch-github-actions@1
  with:
    stack-version: '7.6.2'
    plugins: 'analysis-kuromoji analysis-icu'

action.ymlを作る(これから作るActionがどんな引数を受け取るのか定義する)

  • 今回開発したものを引用します
action.yml
name: 'Run Elasticsearch with Plugins'         # actionの名前,マケプレで表示される.
description: 'Elasticsearch with Plugins'      # actionの説明,マケプレで表示される.
author: 'miyataka'                             # 自分のGitHub IDなど

branding:                                      # マケプレのアイコンを設定する
  icon: 'database'
  color: 'red'

inputs:                                        # Actionを実際にCIで使うときに,渡してほしいパラメータを定義する
  stack-version:
    description: 'The version of Elasticsearch'
    required: true
  plugins:
    description: 'Elasticsearch plugin strings'
    required: false
    default: ''

runs:
  using: 'docker'
  image: 'Dockerfile'
  env:
    STACK_VERSION: ${{ inputs.stack-version }} # inputでもらったパラメータを環境変数に設定してコンテナにわたす
    PLUGINS: ${{ inputs.plugins }}

Dockerfileを作る

  • やっていることはシンプルです.entrypoint.shをイメージに追加しているだけ.
  • 今回諸事情でdocker in dockerをやるので,ベースイメージは内部でdockerコマンドを使えるdocker:stableです
FROM docker:stable
RUN apk add --update bash
COPY entrypoint.sh /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]

コンテナ起動時に実行されるスクリプトを作る

  • さきほど登場したentrypoint.shを実装します
  • hello worldでもなんでもいいのですが,説明の都合上今回開発したものを引用します
#!/bin/bash

set -euxo pipefail

# 必須にした引数が存在するかチェック
if [[ -z $STACK_VERSION ]]; then
  echo -e "\033[31;1mERROR:\033[0m Required environment variable [STACK_VERSION] not set\033[0m"
  exit 1
fi

docker network create elastic

PLUGINS_STR=`echo ${PLUGINS} | sed -e 's/\n/ /g'` # 引数に含まれている改行文字を置換
MAJOR_VERSION=`echo ${STACK_VERSION} | cut -c 1`  # メジャーバージョンを取得

PLUGIN_INSTALL_CMD=""

# pluginsを複数インストールするケースがあるのでfor文でコマンドを組み立てる
if [ "x${PLUGINS_STR}" != "x" ]; then
    ARRAY=(${PLUGINS_STR})
    for i in "${ARRAY[@]}"
    do
        PLUGIN_INSTALL_CMD+="elasticsearch-plugin install --batch ${i} && "
    done
fi

# single node only
if [ "x${MAJOR_VERSION}" == 'x6' ]; then # メジャーバージョンによって起動オプションを分岐する.
  docker run \
    --rm \
    --env "node.name=es1" \
    --env "cluster.name=docker-elasticsearch" \
    --env "cluster.routing.allocation.disk.threshold_enabled=false" \
    --env "bootstrap.memory_lock=true" \
    --env "ES_JAVA_OPTS=-Xms1g -Xmx1g" \
    --env "xpack.security.enabled=false" \
    --env "xpack.license.self_generated.type=basic" \
    --ulimit nofile=65536:65536 \
    --ulimit memlock=-1:-1 \
    --publish "9200:9200" \
    --detach \
    --network=elastic \
    --name="es1" \
    --entrypoint="" \
    docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} \
    /bin/sh -vc "${PLUGIN_INSTALL_CMD} /usr/local/bin/docker-entrypoint.sh"
elif [ "x${MAJOR_VERSION}" == 'x7' ]; then
  docker run \
    --rm \
    --env "node.name=es1" \
    --env "cluster.name=docker-elasticsearch" \
    --env "cluster.initial_master_nodes=es1" \
    --env "discovery.seed_hosts=es1" \
    --env "cluster.routing.allocation.disk.threshold_enabled=false" \
    --env "bootstrap.memory_lock=true" \
    --env "ES_JAVA_OPTS=-Xms1g -Xmx1g" \
    --env "xpack.security.enabled=false" \
    --env "xpack.license.self_generated.type=basic" \
    --ulimit nofile=65536:65536 \
    --ulimit memlock=-1:-1 \
    --publish "9200:9200" \
    --detach \
    --network=elastic \
    --name="es1" \
    --entrypoint="" \
    docker.elastic.co/elasticsearch/elasticsearch:${STACK_VERSION} \
    /bin/sh -vc "${PLUGIN_INSTALL_CMD} /usr/local/bin/docker-entrypoint.sh"
fi

# 上記で起動したコンテナに対して,curlで死活確認するコンテナを立ち上げる
docker run \
  --network elastic \
  --rm \
  appropriate/curl \
  --max-time 120 \
  --retry 120 \
  --retry-delay 1 \
  --retry-connrefused \
  --show-error \
  --silent \
  http://es1:9200

sleep 10

echo "Elasticsearch up and running"

今回開発したAction自体をテストするCIワークフローを定義する

  • すでにActionを使った事がある場合にはご存知でしょうが,.github/workflows/*.ymlを配置するとCIを実行してくれますね.
  • 今回開発したAction自体も思ったとおりに動くか検証するためのCIを作りました
name: Elasticsearch GitHub Action

on: [push]

jobs:
  run-action:
    name: Start Elasticsearch
    runs-on: ubuntu-latest
    strategy:
      matrix:
        elasticsearch: ["6.4.3", "7.6.2"]
    steps:
      - name: Checkout
        uses: actions/checkout@v1

      - name: Configure sysctl limits
        run: |
          sudo swapoff -a
          sudo sysctl -w vm.swappiness=1
          sudo sysctl -w fs.file-max=262144
          sudo sysctl -w vm.max_map_count=262144

      - name: Start Elasticsearch                     # 重要なのはこの部分
        uses: ./
        with:
          stack-version: ${{ matrix.elasticsearch }}
          plugins: |
            analysis-kuromoji
            analysis-icu

      - name: Elasticsearch is reachable
        run: |
          curl --verbose --show-error http://localhost:9200

マーケットプレイスに公開する

  • 動作確認もできたら,あとは公開するだけです.
  • ここまでの手順を踏んでいれば,以下のような表示がされているはずです. publish-github-action-to-markeplace-button.png
  • このボタンを押して,指示に従い公開しましょう.
  • ここは公式docをみたほうがいいですね

参考と補足

最後に

すでにたくさんActionsが公開されているのですが,まだまだかゆいところに手が届かない感じのものも多いです.
OSS開発するにはまだまだブルーオーシャンです.皆で開発&公開してよりよい開発効率を目指しましょう!

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

Dockerでdocker-compose upができないエラーについて

環境

Doker 19.03.8
MacOS 10.15.4

なぜかdocker-compose upでエラーになってしまう場合

下記のような絵ラーが出てしまった場合

$ docker-compose up

#(省略)

ERROR: for recipegram_web_1  Cannot start service web: driver failed programming external connectivity on endpoint recipegram_web_1 (2114b3f64e45c6f24835b0b49c1aac852d41b5f6c952181dc7b660f9105b79c6): Bind for 0.0.0.0:3000 failed: port is already allocated

ERROR: for web  Cannot start service web: driver failed programming external connectivity on endpoint recipegram_web_1 (2114b3f64e45c6f24835b0b49c1aac852d41b5f6c952181dc7b660f9105b79c6): Bind for 0.0.0.0:3000 failed: port is already allocated
ERROR: Encountered errors while bringing up the project.

いつもはできてるバズなのにおかしなぁ...と思ってよく読んでみると「接続に失敗し、立ち上げ中にエラーが発生しました」という内容が出てきました...
おかしいなぁ...と思い。考えてみると他のアプリをDockerで立ち上げていたことに気がつきます!

なので起動中のアプリのディレクトリに移動して$ docker-compose stopをして完了です。単純なエラーでした^_^;

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

【Docker】GolangからMySqlへ接続してみた

やりたいこと

GolangコンテナからMySqlコンテナに接続したい!

環境

docker 19.03.8
docker-compose 1.25.5

リポジトリ

https://github.com/atsugitakuya/go-mysql-docker.git

フォルダ階層

root /
 ├ app /
 | └ main.go
 ├ docker /
 | └ Dockerfile
 └ docker-compose.yaml

main.go作成

今回はgormというORMライブラリを使って接続していく。
https://gorm.io/

/app/main.go
package main

import (
    "fmt"
    "net/http"

    _ "github.com/go-sql-driver/mysql"
    "github.com/jinzhu/gorm"
)

func main() {
    http.HandleFunc("/", index)
    http.ListenAndServe(":80", nil)
}

// mysqlconnectionが確認できれば「DB接続成功」が表示される
// 接続に失敗時はエラーメッセージを吐く
func index(w http.ResponseWriter, r *http.Request) {
    _, err := sqlConnect()
    if err != nil {
        fmt.Fprintf(w, err.Error())
    } else {
        fmt.Fprintf(w, "DB接続成功")
    }
}

// connetion確認func
func sqlConnect() (database *gorm.DB, err error) {
    DBMS := "mysql"
    USER := "root"
    PASS := "golang"
    PROTOCOL := "tcp(mysql:3306)"
    DBNAME := "mysql"

    CONNECT := USER + ":" + PASS + "@" + PROTOCOL + "/" + DBNAME + "?charset=utf8&parseTime=true&loc=Asia%2FTokyo"
    return gorm.Open(DBMS, CONNECT)
}

Dockerfile作成

今回使用するgormとmysqlのdriverをインストールしている。
なんかgitがないと動かないっぽい。あとRunコマンドは少なくした方がいいが良い。
多分もっと良い方法があるはず....

/docker/Dockerfile
FROM golang:alpine
# フォルダ作成
RUN mkdir /app
# 作成したフォルダ内にmain.goを配置
COPY ./app /app
# 作業場所を/appに設定(main.goがある場所)
WORKDIR /app
# 必要ライブラリをインストール
RUN apk add --no-cache git
RUN go get "github.com/go-sql-driver/mysql"
RUN go get -u github.com/jinzhu/gorm
# main.goをbuild
RUN go build -o main . 
# port開放
EXPOSE 80
# app開始
CMD ["/app/main"]

docker-compose.yaml作成

golangとmysqlを動かすためのdocker-compose。特に説明することない。

/docker-compose.yaml
version: '3'

services:
  golang:
    build: 
      context: .
      dockerfile: ./docker/Dockerfile
    ports:
    - "80:80"
    container_name: go-sample
    depends_on:
    - mysql
  mysql:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: golang
      MYSQL_USER: golang
      MYSQL_PASSWORD: golang
      MYSQL_DATABASE: golang
    container_name: mysql

実行し、DBの接続確認を行う

zsh
# docker-compose.yamlのある階層で実行
$docker-compose up -d
....
# 立ち上がったよ!メッセージが出たらOK
Creating mysql ... done
Creating go-sample ... done

localhostに接続すると、「DB接続成功」が出るはず...

スクリーンショット 2020-05-17 17.48.01.png

接続成功!!!!
意外と簡単に接続できた...さすがGoだな...

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

COS(コンテナ最適化OS)でDockerの利用できるディスク容量を増やす

はじめに

GCPだとcreate-with-containerを使う事でCOS(Container-Optimized OS)を利用したコンテナ用のインスタンスを作る事ができます。
イメージ名とかも指定できるので、小規模なコンテナ運用ならGKEでやるより簡単かと思います。

ただデフォルトのdiskサイズが10GBなので大きめのDocker Imageをビルドすると下記のように容量不足のエラーが出ます。

Error processing tar file(exit status 1): write .... : no space left on device

なので、今回はビルドの容量を確保するためにCOSに永続化ディスクを追加したのでそのやり方のメモになります。

戦略

  • boot diskのサイズ変更ではなく新規ディスクの追加
  • /var/lib/dockerの上書きではなくdaemon.jsでイメージの置き場所を変える

まずboot diskのサイズ変更では無く新規ディスクの追加をしているのは、その方が後からDocker領域だけ容量変更がしやすいのとインスタンスを作り直してもイメージ領域を使いまわせるからです。
特に、実験的にパラメータを変更してインスタンスを作り直すのを頻繁にやってるのでboot diskとは分けておく方が便利そうです。

また、/var/lib/dockerに上書きマウントしても良いのですが、予期せぬ問題が起こっても嫌なので設定ファイルを真っ当に変更します。

永続化ディスクの作成とマウント

まずは永続化ディスクを作ります。

$ gcloud compute disks create disk4docker \
     --size 20 --type pd-standard --zone asia-northeast1-b

続いてマシンにアタッチします。

$ gcloud compute instances attach-disk instance001 \
     --disk disk4docker --zone asia-northeast1-b

SSHでサーバに入ってlsblkコマンドでアタッチされたディスクを確認します。sdbとかsdcとかが追加されているはずです。

$ sudo lsblk

最後にフォーマットしてマウントします。

$ sudo mkfs.ext4 -m 0 -E lazy_itable_init=0,lazy_journal_init=0,discard /dev/sdb
$ sudo mkdir -p /mnt/disks/docker_data
$ sudo mount -o discard,defaults /dev/sdb /mnt/disks/docker_data
$ df /mnt/disks/docker_data
Filesystem     1K-blocks  Used Available Use% Mounted on
/dev/sdb        20511312 45080  20449848   1% /mnt/disks/docker_data

これで追加したディスクがOS上からアクセスできるようになりました。

Dockerイメージの置き場所を変更する

Dockerイメージの置き場所は通常は/var/lib/dockerですがこちらを/mnt/disks/docker_dataに変更します。

daemon.jsonがDockerの設定ファイルになるのでこちらにdata-rootを追加します。

/etc/docker/daemon.json
{
        ...
        "data-root": "/mnt/disks/docker_data"
}

設定を反映させるためにDokcerデーモンを再起動します。

$ sudo systemctl restart docker
$ ls -l /mnt/disks/docker_data

/mnt/disks/docker_dataoverlay2volumesなどが追加されていれば成功です。

起動スクリプトに設定を反映する

COSでは/etcの設定は再起動時に毎回初期化されます。なので、起動スクリプトに修正を入れて起動時マウントなどをしなおします。

まず、起動スクリプトは以下のように書きます。

config.sh
#!/bin/bash

mount -o discard,defaults /dev/sdb /mnt/disks/docker_data
cat <<EOF > /etc/docker/daemon.json
{
    "data-root": "/mnt/disks/docker_data",
    "live-restore": true,
    "storage-driver": "overlay2",
    "mtu": 1460
}
EOF
systemctl restart docker

続いて起動スクリプトを追加して、インスタンスを再起動します。

$ gcloud compute instances add-metadata instance001 \
    --metadata-from-file startup-script=config.sh  \
    --zone=asia-northeast1-b 
$ gcloud compute instances stop instance001 --zone asia-northeast1-b 
$ gcloud compute instances start instance001 --zone asia-northeast1-b 
$ df -h /mnt/disks/docker_data/
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdc         20G  650M   19G   4% /mnt/disks/docker_data

これで無事Dockerのビルド時に利用するディスクサイズを増やせました

Diskをリサイズしてみる

せっかくなのでディスクのリサイズも試してみます。

まずgcloudコマンドでディスクサイズを増やします。なお減らすことは出来ないのでコストを考えると小刻みに増やす方が良いかもしれないです。

$ gcloud compute disks resize disk-theia-docker --size 100 --zone=asia-northeast1-b 

これだけではOSから見える領域としては増えていないのでサーバにログインしてファイルシステムサイズを変更します。

$ sudo resize2fs /dev/sdb
$ df -h /mnt/disks/docker_data/
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdb         99G  6.4G   92G   7% /mnt/disks/docker_data

まとめ

さて、COS上でディスク容量を増やす方法を試してみました。
ただ、コンテナのボリュームにディスクを追加する場合はもう少しシンプルに出来ますし、あまりする必要がない作業な気がします。これ。
この作業が必要なのはCOS上でdocker buildをガッツリやるときだけです。それであればローカルビルドは捨ててcloud-buildを使ってしまうと言うのも手かなと思うので、その辺のもう少しクラウドネイティブな方法を考えていきたいです。

それではHappy Hacking!

参考

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

[WIP]scrapinghubで独自のdocker imageを使う方法

事前準備

また、scrapinghubのCLIコマンドとなるshubをインストールすること(pipでインストール可)

pip install shub

また、Scrapy Cloud Professional(9ドル/月unit)への課金が必要となります

Scrapy Cloud runs your spiders in Docker containers and allows you to build custom images to deploy there. This feature is currently only available for paying customers (you need to be subscribed to at least 1 paid Scrapy Cloud Unit which costs $9). Crawlera and Splash subscriptions are not considered, as the deploy is a Scrapy Cloud feature.

https://support.scrapinghub.com/support/solutions/articles/22000200425-deploying-custom-docker-images-on-scrapy-cloud より)

元々、scrapinghubは無料でも使えましたが、このプランなら1つ9ドル/月ごとにインスタンスを増やせますし、スクレイピングのタスクが1時間で停止するのが無制限になります

Dockerfileを作る

(※scraping hubプロジェクトの設定をした後の話になります)

scraping hubで使用されているDockerイメージの設定をベースとしたテンプレートが利用できます

以下のコマンドを打つことで、scrapinghubに対応したイメージが簡単にカスタマイズできるのでおすすめです

shub image init

すると以下のようなDockerfileが生成されます。

使用する依存ライブラリのインストールの記述を書いたり、使用しているpythonのバージョンに合わせてイメージのバージョンを適宜変更すればよいかと

scrapinghub-stack-scrapyのバージョンについてはこちらのgithubリポジトリを参照し、自分の環境に合わせて使用したいバージョンをTagsより探しましょう。

FROM scrapinghub/scrapinghub-stack-scrapy:1.3
ENV TERM xterm
ENV SCRAPY_SETTINGS_MODULE ai_usecase_db.settings
RUN mkdir -p /app
WORKDIR /app
COPY ./requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
COPY . /app
RUN python setup.py install

もちろんローカル環境でビルドして動かすこともできるので、事前にローカル上で動作確認するのをお勧めします

あとはscrapinghub-entrypoint-scrapyというscrapinghub側のentrypointコマンドを用意してやる必要があります。pipでインストールできるのでrequirements.txtに書き込むといいです

pip install scrapinghub-entrypoint-scrapy
pip freeze > requirements.txt

もしくはDockerfile内に以下を追記

RUN pip install scrapinghub-entrypoint-scrapy

Dockerイメージをデプロイ

デプロイの仕方について、scrapinghubのdocker registoryにイメージを上げるため、事前にログインが必要になります。ログインの仕方について、公式の回答は

If using --reauth flag did not help, then try to re-login manually via "docker login images.scrapinghub.com" with username = your SH API key and password = a single space.

https://support.scrapinghub.com/support/solutions/articles/22000232799-errors-while-deploying-custom-image-to-scrapy-cloud より)

要約すると

docker login images.scrapinghub.com

コマンドで認証ができて、問われるユーザー名とパスワードはそれぞれ(自分のscrapinghubプロジェクトのAPIキー)、(半角スペース1文字)となります。

ログインに成功したらscrapinghub.ymlで用意したDockerfileを使うように設定を変更しましょう

scrapinghub.yml
image: true  # この行を追加して自分で用意したDockerfileを使う
project: your_project_id
requirements:
  file: requirements.txt
#stack: scrapy:1.8-py3   使用するstackの行を削除

ここから先で詰まっていて、まだうまく言っていませんが、デプロイは以下の手順になるかと

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

scrapinghubで独自のdocker imageを使う方法

事前準備

また、scrapinghubのCLIコマンドとなるshubをインストールすること(pipでインストール可)

pip install shub

また、Scrapy Cloud Professional(9ドル/月unit)への課金が必要となります

Scrapy Cloud runs your spiders in Docker containers and allows you to build custom images to deploy there. This feature is currently only available for paying customers (you need to be subscribed to at least 1 paid Scrapy Cloud Unit which costs $9). Crawlera and Splash subscriptions are not considered, as the deploy is a Scrapy Cloud feature.

https://support.scrapinghub.com/support/solutions/articles/22000200425-deploying-custom-docker-images-on-scrapy-cloud より)

元々、scrapinghubは無料でも使えましたが、このプランなら1つ9ドル/月ごとにインスタンスを増やせますし、スクレイピングのタスクが1時間で停止するのが無制限になります

Dockerfileを作る

(※scraping hubプロジェクトの設定をした後の話になります)

scraping hubで使用されているDockerイメージの設定をベースとしたテンプレートが利用できます

以下のコマンドを打つことで、scrapinghubに対応したイメージが簡単にカスタマイズできるのでおすすめです

shub image init

すると以下のようなDockerfileが生成されます。

使用する依存ライブラリのインストールの記述を書いたり、使用しているpythonのバージョンに合わせてイメージのバージョンを適宜変更すればよいかと

scrapinghub-stack-scrapyのバージョンについてはこちらのgithubリポジトリを参照し、自分の環境に合わせて使用したいバージョンをTagsより探しましょう。

FROM scrapinghub/scrapinghub-stack-scrapy:1.3
ENV TERM xterm
ENV SCRAPY_SETTINGS_MODULE ai_usecase_db.settings
RUN mkdir -p /app
WORKDIR /app
COPY ./requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir -r requirements.txt
COPY . /app
RUN python setup.py install

もちろんローカル環境でビルドして動かすこともできるので、事前にローカル上で動作確認するのをお勧めします

Dockerイメージをデプロイ

デプロイの仕方について、scrapinghubのdocker registoryにイメージを上げるため、事前にログインが必要になります。ログインの仕方について、公式の回答は

If using --reauth flag did not help, then try to re-login manually via "docker login images.scrapinghub.com" with username = your SH API key and password = a single space.

https://support.scrapinghub.com/support/solutions/articles/22000232799-errors-while-deploying-custom-image-to-scrapy-cloud より)

要約すると

docker login images.scrapinghub.com

コマンドで認証ができて、問われるユーザー名とパスワードはそれぞれ(自分のscrapinghubプロジェクトのAPIキー)、(半角スペース1文字)となります。

ログインに成功したらscrapinghub.ymlで用意したDockerfileを使うように設定を変更しましょう

scrapinghub.yml
image: true  # この行を追加して自分で用意したDockerfileを使う
project: your_project_id
requirements:
  file: requirements.txt
#stack: scrapy:1.8-py3   使用するstackの行を削除

あとは以下のようにdeployコマンドを通すことでビルド・プッシュをしつつデプロイしてくれます

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

TeX Live 2020 用の日本語用Dockerコンテナ

はじめに

TeX Live の日本語用 Docker コンテナとして alpine ベースの paperist/alpine-texlive-ja を使用しています。

TeX Live 2020 がリリースされたのを機にフォークして、TeX Live 2020 用のコンテナを作成し、DockerHub に toshiara/alpine-texlive-ja としてアップロードしました。

  • 本当はDockerファイルのプルリクエストを送ったのですが、忙しいためか気いてもらえなかったので自分で作成しました。

TeX Live 2020 の特徴(超抜粋)

TeX Live 2020 では原ノ味フォントがデフォルトとなりました
- 別途 Noto フォントをコンテナに追加して使用していたのですが、その必要がなくなりました。
- これまでの TeX Live 2019 でも問題ないのですが、TeX Live 2020 を使用するのはこの点が私にとっての理由です。

インストールおよび使用例

必要なパッケージの追加

実際には、toshiara/alpine-texlive-ja-plus のように個人的に必要なパッケージを追加して使用しています。

インストール

docker pull toshiara/alpine-texlive-ja

タグは今の所latest20202020.5.10(ビルドした日付)を用意しています。
コンテナを変更した場合には日付のタグだけを更新する予定です(今の所その予定はないです)。

使用例

docker run --rm -it -v $PWD:/workdir toshiara/alpine-texlive-ja platex --version
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DockerでWebサーバーを構築する

1.Dockerで仮想環境を作成する方法

Dockerをインストールした後、アプリケーションの仮想環境を作成します。
方法は2つあります。

  • Docker Hub からイメージをダウンロードする
  • 自分でコンテナを作成して構築する

今回は、手始めに簡単にできるDocker Hubから作成済みのコンテナをダウンロードして環境を構築します。

2.Docker Hubとは

Docker Hubは、クラウド上に用意されているアプリケーションやサービス・コンテナの配布、公開などを行っています。
運営は、docker社が行っています。
(参考)http://docs.docker.jp/docker-hub/overview.html
サイトにアクセスするにはユーザー登録がいりますが、無償でも参加できます。
また、Docker Hubに登録されているアプリケーションを検索することができます。

3.Docker HubからWebサーバーをダウンロードして構築する

今回は、Webサーバとしてapacheを使用します。

  • dockerが起動していることを確認し、以下のコマンドを実行してダウンロードします。
# docker pull httpd

実行例

# docker pull httpd
Using default tag: latest
latest: Pulling from library/httpd
afb6ec6fdc1c: Pull complete 
5a6b409207a3: Pull complete 
41e5e22239e2: Pull complete 
9829f70a6a6b: Pull complete 
3cd774fea202: Pull complete 
Digest: sha256:db9c3bca36edb5d961d70f83b13e65e552641e00a7eb80bf435cbe9912afcb1f
Status: Downloaded newer image for httpd:latest
docker.io/library/httpd:latest
  • ダウンロードされたことを確認します。
# docker images

実行例

# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
httpd               latest              d4e60c8eb27a        31 hours ago        166MB
centos              latest              470671670cac        4 months ago        237MB
hello-world         latest              fce289e99eb9        16 months ago       1.84kB

「httpd」 があることを確認します。

4.Webサーバーを起動する。

先ほどダウンロードしたapacheを起動し、動作を確認します。

# docker run -d -p 81:80 httpd

docker コマンドの紹介は別途しますが、ここで意識するオプションは3つです。
 -d   → コマンドをバックグラウンドで実行する
 -p (サーバーのポート):(コンテナのポート) → ポートの紐づけ
       上記の例では、サーバー81番ポートと、コンテナ(httpd)80番ポートを紐づけます。
       つまり、コンテナにWebサーバにアクセスするときは、81番ポートに接続するということになります。
 httpd 実行するイメージ

[root@dockerl ~]# docker run -d -p 81:80 httpd
b8fd34885a6c2828f10f4db4b0dc960688bea07818e9d1013d4da49e5e1e9a1b

実際に、ウェブブラウザでアクセスしてみます。
URLは以下になります。
http://(サーバのIPアドレス):81/

画面が出れば成功です。
ちなみに、私の環境では「It's Works!」というテキストだけの画面が出ました。

5.Webサーバの停止

Dockerのコンテナを停止は以下のようにします。

  • コンテナのプロセス番号を調べる
  • プロセス番号を指定して停止させる
# docker ps

# docker stop (コンテナID)

実行例

# docker ps
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                NAMES
b8fd34885a6c        httpd               "httpd-foreground"   6 minutes ago       Up 5 minutes        0.0.0.0:81->80/tcp   eager_noether
# docker stop b8fd34885a6c    # stop の後には、docker psのCONTAINER IDを指定する。
b8fd34885a6c
# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
#

docker stop の後のdocker ps でhttpd が消えていれ成功です。

6.コンテナに独自の設定を行う

ダウンロードしたhttpdは、初期設定しが入っています。
独自の設定をするには、ローカルサーバー上にhttpdの設定ファイルやコンテンツを保存し、そこを参照させます。
その方法は、docekr run の -v オプションを使用します。

 -v "(サーバーのパス):(コンテナに配置するパス)" →ファイル、ディレクトリの紐づけ
      パスはディレクトリ指定の場合は必ず最後に/ を入れてください。
      /を入れない場合はファイルと認識されるようです。

例)

# docker run -d -p 81:80 -v "/tmp/httpdtest:/usr/local/apache2/htdocs" httpd

/tmp/httpdtest にindex.html やコンテンツを保存したうえで上記を実行すると、保存したファイルが表示されます。
なお、-v オプション、-pオプションは1つのコマンドで複数選択できます。
例えばコンテンツが複数のディレクトリに分かれている。httpd.conf を変更したいといった場合、
複数のポートを使用している場合にも適用できます。

今回使ったオプションのまとめ

 -d   → コマンドをバックグラウンドで実行する
 -p (サーバーのポート):(コンテナのポート) → ポートの紐づけ
       上記の例では、サーバー81番ポートと、コンテナ(httpd)80番ポートを紐づけます。
       つまり、コンテナにWebサーバにアクセスするときは、81番ポートに接続するということになります。
 -v "(サーバーのパス):(コンテナに配置するパス)" →ファイル、ディレクトリの紐づけ
       パスはディレクトリ指定の場合は必ず最後に/ を入れてください。
       /を入れない場合はファイルと認識されるようです。
 httpd 実行するイメージ

.7参考

dockerやdockerコマンドについての詳細は、下記を参照してください。
  Docker ドキュメント日本語化プロジェクト : http://docs.docker.jp/index.html
  Dockre Docs : https://docs.docker.com/

以上です。

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

DockerでGhostscript対応LaTeX環境構築

はじめに

普段はmacメインだけれども、在宅勤務で久々にWindows環境を使っています。
Windows環境にも論文執筆のためのLaTeX環境を導入しようと思いましたが、面倒なのでDocker上に構築することにしました。

調べてみると、既にQiitaに記事を書いてくださっている方がいました。

DockerでらくらくLaTeX環境構築

しかし、EPS画像を含む英語論文をpdflatexしようとしたところうまくいきませんでした。

本記事では上記記事で紹介されているDockerイメージをGhostscript対応に拡張した環境を構築していきます。
などと大仰なことを書いていますが、作成したDockerイメージは公開しているので、これをpullしてくるだけです。

検証環境

以下の2つの環境で検証しています。

  • Docker version 19.03.8, build afacb8b with macOS 10.15.4 on Mac mini (2018)
  • Docker version 19.03.8, build afacb8b with Windows 10 Education version 2004 (build 19041.264) on Intel NUC

導入方法

Dockerはあらかじめインストールしておきましょう。
あとはDockerイメージをpullしてくるだけです。

$ docker pull pman0214/alpine-texlive-ja-epspdf 

取得しているDockerイメージはここで公開しているものです。

pman0214/alpine-texlive-ja-epspdf

上記記事で紹介されているpaperist/alpine-texlive-jaにGhostscriptとepstopdfを追加しています。
paperist/alpine-texlive-jaにGhostscriptとepstopdfを直接インストールしようとしたところ、TeXLiveのバージョンが古いためにインストールできませんでした。
このためTeXLive2020で新たにDockerイメージを作りました。

現時点での最新バージョンpman0214/alpine-texlive-ja-epspdf:2020は圧縮サイズで約610MBです。

使い方

docker pullした後は以下の例のようにdockerコンテナを起動して各種texコマンドを実行してください。

$ docker run --rm -it -v $PWD:/workdir pman0214/alpine-texlive-ja-epspdf latexmk main.tex

試しに使ってみる

今回はEPSファイルを参照しているダミーtexファイルを使います。
EPSファイルも含めてGistに置いてあるので、これを取得して使います。

pdflatex with eps testing

main.tex
%#!pdflatex main.tex
\documentclass[twocolumn]{article}
\usepackage{graphicx}

\title{Test Report}
\author{pman0214}

\begin{document}
\maketitle
\section{Introduction}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec in justo
semper, sagittis elit vel, eleifend arcu.
Phasellus accumsan id ipsum non varius.
Suspendisse nec nulla nunc.
Pellentesque rutrum commodo lacinia.
Sed molestie ullamcorper tellus, in aliquet mauris egestas non.
Maecenas sed lectus ac neque eleifend fermentum.
Donec id purus felis.
Nam ornare sagittis ullamcorper.

Donec commodo enim nec leo tincidunt varius.
Aliquam vulputate sit amet nibh nec facilisis.
Aliquam lobortis nec urna vel convallis.
Fusce facilisis libero leo, sed pretium dui imperdiet id.
Duis in est et nunc molestie vestibulum vel eget nunc.
Suspendisse potenti.
Mauris scelerisque magna at ex scelerisque, vel tempus turpis eleifend.
Phasellus efficitur elementum ex vel ultrices.
Sed eget arcu magna.
Maecenas dignissim imperdiet lorem, sit amet gravida lorem bibendum at.
Aenean non blandit metus, id viverra velit.
Integer ut sapien sapien.
Sed quam nisi, vehicula quis nunc ullamcorper, molestie accumsan augue.

\begin{figure}[bt]
 \centering
 \includegraphics[width=.8\hsize]{dummy.eps}
 \caption{Dummy figure}
\end{figure}
\end{document}

Gistから取得したZipファイルを展開したディレクトリに入り、以下を実行すればEPS画像を含むmain.pdfが出力されます。

$ docker run --rm -it -v $PWD:/workdir pman0214/alpine-texlive-ja-epspdf latexmk main.tex

おわりに

本記事では、eps画像を含むtexファイルをタイプセットしてPDFを生成できる環境をDockerを用いて構築しました。
新しいmacを導入する際もこれを使うと導入が楽で幸せになれそうです。

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

dockerでnuxtの開発環境を作る

この記事の目的

  • dockerでnuxtの開発環境を作っていく

参考にした記事

「Nuxt.js のプロジェクトを Docker (Docker Compose) を使って動かす」
https://yopinoji.com/docker-for-nuxt-js

詰まったところ

core-js関連のエラー

ver2はサポートを打ち切ってしまったらしいがこのver2でないとエラーが出てしまうのでinstallする必要がある。

npm i --save core-js@2

上記コマンドを打った後にbuildをもっかいする

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

Dockerで用意した開発環境のキャッシュが邪魔で開発が捗らないときに見直すべきこと(Nginx + PHP-FPM)

Dockerで下記のイメージを使用して開発環境を用意しました。

  • nginx:latest
  • bitnami/php-fpm:latest

キャッシュが効きすぎてしまい、ブラウザキャッシュを削除してもデータが更新されない状態でした。時間計測してみると60秒ごとにファイルを見に行っているような挙動ということがわかりました。このような状況を解決するための備忘録です。

Nginxが原因ではなかった

Nginxを初めて使ったので、こいつが原因かと思っていましたが間違っていました。
PHP-FPMイメージでデフォルトで有効になっている拡張モジュールが原因でした。

Zend OPcacheを無効にすればOK

Zend OPcacheというキャッシュ拡張モジュールが働いていたために爆速キャッシュが効いていました。

Zend OPcacheを無効にする

php.iniの中にある opcache.enable = 1 という箇所を opcache.enable = 0 としてサービスを再起動するだけです。

以上でキャッシュが効かない状態で開発が可能となります!

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

超基礎からの 速習 Docker (2)

Whale, Docker

本稿は、Christffer Noring さん (@chris_noring) の Learn Docker, from the beginning, part II を翻訳し、分かりやすいように少しだけ追記、サンプルコードの実行上の補足等を行ったものです。シリーズ翻訳の意図については 超基礎からの 速習 Docker (1) の冒頭に掲載しています。併せてご参照くださいませ。

超基礎からの 速習 Docker シリーズ一覧

  • 超基礎からの 速習 Docker (1)
    • なぜ Docker なのか、コンテナーやイメージ、Dockerfile の基本コンセプトの解説、もちろん、それらを管理するのに必要なコマンド群もカバーしています。
  • 超基礎からの 速習 Docker (2)
    • いまここ。
  • 超基礎からの 速習 Docker (3)
    • データベースをコンテナ化し、レガシーなやり方及び新しいやり方である Network を用いて他のコンテナから連絡可能にします。
  • 超基礎からの 速習 Docker (4)
    • Docker Compose を用いた複数サービスの管理方法を解説します(その1)
  • 超基礎からの 速習 Docker (5)
    • Docker Compose を用いた複数サービスの管理方法を解説します(その2)

速習 Docker パート2へようこそ。できればパート1を読んで Docker コア コンセプトと基本コマンドについての基本的な理解が出来ているか、他で知っているかしてくれていると良いですね。

本稿では、以下のトピックをカバーしています。

  • 復習、そして課題の紹介 パート1で学んだことを復習しましょう。そして、Volume を使わないことがいかに骨が折れるかお伝えしましょう。
  • 永続的データ Volume は、僕らが作るファイル群や僕らが中身をいじるデータベース(e.g Sqlite)を永続化するのに利用できます。
  • WORKDIR を Volume に変える Volume は、更新あるごとにコンテナーをセットアップしたり、削除したりすることなしにアプリ作業を続ける良い方法も提供してくれます。

訳注
多くの Docker 文章で "Persist data" を "永続的データ" と翻訳していますが、字面では少し分かりにくいですね。この後の Volume の実地で明らかになりますが、要はコンテナーが削除されてもそのまま残っているデータのことで、それを "Persist"、"永続的" と言ってます。

リソース

Docker を使う事、コンテナー化は、一枚岩をマイクロサービスに分解していくことです。このシリーズのいたるところで僕らは Docker やそのコマンド体系をマスターするために学ぶことになります。そうすれば、きっと君は自作のコンテナーをプロダクション環境で使いたくなるでしょう。その環境は大抵クラウド上にあります。十分な Docker 経験を積んだと思ったなら、次のリンクで Docker をクラウドでどのように活用できるか、ご確認してみると良いと思います。

  • Azure 無料アカウントのサインアップ プライベート レジストリのようなクラウドのコンテナーを使うには、無料 Azure アカウントが必要でしょう。
  • クラウドのコンテナー クラウドのコンテナーについて他に知っておくべきことについて網羅する概要ページです。
  • 自作コンテナーをクラウドにデプロイ 今の Docker スキルをレバレッジしてクラウド上でサービスを動かすことがいかに簡単かを示すチュートリアル。
  • コンテナー レジストリの作成 自作 Docker イメージを Docker Hub に入れられますが、クラウドのコンテナー レジストリも可能です。自作イメージをどこかにストアして、一瞬でレジストリから実際のサービスをできるようにすることは凄くないですか?

復習、そして Volume を使わないことの問題

OK、このシリーズの最初のパートで作った express ライブラリーを使った Node.js アプリケーションをそのまま使っていきましょう。

このセクションでは次のことを行います:

  • コンテナーの実行 コンテナーをスタートすることで、最初のパートで学んだ Docker 基本コマンドをいくつか繰り返します。
  • アプリの更新 僕らのソースコードを更新し、コンテナーをスタート、ストップ。このやり方がいかに骨が折れるか実感してもらいます。

コンテナーの実行

アプリケーションが大きくなるにつれて、ルートを追加したくなったり、特定のルートでレンダリングするものを変えたりしたくなります。ここまでのソースコードを見てみましょう:

app.js
const express = require('express')

const app = express()

const port = process.env.PORT

app.get('/', (req, res) => res.send('Hello World!'))

app.listen(port, () => console.log(`Example app listening on port ${port}!`))

基本コマンドを覚えているか見てみましょう。Let's Type:
docker ps

% docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

OK、何もないようですね。前回使ったかどうかに関係なく、最後に僕らは docker stop または socker kill を使ってクリーンアップしましたね。ですので、コンテナーをビルドしなければなりません。僕らはどんなイメージを持っているか見てみましょう。
docker images

% docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
chrisnoring/node    latest              177e657fae6e        6 days ago          943MB

OK、僕らのイメージがありますね。コンテナーを作って実行しましょう。
docker run -d -p 8000:3000 chrisnoring/node
これは、コンテナーを作り、ポート 8000 、detached モードで実行します。-d フラグを指定してくれてありがとう!

訳注
あれっ、パート1では daemon モードって言ってなかったっけ・・? -d は --detached の略式なので、detached モードの方であってそうだけど。

% docker run -d -p 8000:3000 chrisnoring/node
a093abebf85dd157f35413a5398b0bbc23a5013e90acbca0a109791db0840ec3

コンテナー ID を取得しました。良いですね。http://localhost:8000 にアクセスしてアプリを見つけられるか見てみましょう。
Hello World
OK、良いですね。いよいよ次のステップ、ソースコードを更新する準備が整いました。

アプリの更新

デフォルトのルートを、Hello Chris とレンダリングするように変えましょう。次のように加えます。

app.get('/', (req, res) => res.send('Hello Chris!'))

OK、変更を修正したら、ブラウザに戻ってみよう。すると、「Hello World」のままだって気が付きますよ。まだ僕らの変更はコンテナーに反映されてないようです。こうなったら、コンテナーを落として、削除、イメージをリビルド、そしてコンテナーを再び実行する必要があります。すべてのコマンドを実行しなければならない都合上、ビルドしてコンテナーを実行するとき名前で行えるようにすると良いですね。次のようにコンテナーを実行する代わりに:
docker run -d -p 8000:3000 chrisnoring/node
こうタイプしましょう:
docker run -d -p 8000:3000 --name my-container chrisnoring/node
この意味するところは、コンテナーが my-container と言う名前を得ることで、コンテナー ID の代わりにこの名前でコンテナーを参照できるようにしたのです。セットアップや削除にコンテナーIDと同じように使えるので、ちょっと良い感じですね。(訳注:以下いずれも Node.js プロジェクトのフォルダで実行ください。)

docker stop my-container // this will stop the container, it can still be started if we want to

docker rm my-container // this will remove the container completely

docker build -t chrisnoring/node . // creates an image

docker run -d -p 8000:3000 --name my-container chrisnoring/node

こんな感じでコマンドを繋ぐとことも出来ます:

docker stop my-container && docker rm my-container && docker build -t chrisnoring/node . && docker run -d -p 8000:3000 --name my-container chrisnoring/node

訳注
&& によるコマンドのチェーンは PowerShell v7 以降のサポートになります。Windows で PowerShell またはコマンド プロンプトをご利用の皆様はご注意ください。なお、&& はここしか出てこないけどね。

これを最初に見た時の印象は「わお」です。コマンドだらけです。特に開発フェーズにある時にはもっといい方法があるはずです。

WOW

そうです、もっと良い方法があります。それでは Volume について見て行きましょう。

Volume を使う

Volume や データ Volume は、ファイルを書いて永続化できる場所を作る方法です。どうしてそうしたいのでしょう?開発時、アプリケーションの状態はそのままにしたいですよね。最初から始める必要なんてない。一般に、log ファイルや JSON ファイル、データベース (SQLite) までも Volume に保存したいでしょう。
Volume を作ることはとても簡単です。たくさんの方法がありますが、主に二つの方法があります:

  • コンテナーを作成する前に、
  • だらだらする e.g コンテナーを作っている間

Volumeの作成と管理

Volumeを作るには以下のようにタイプします:
docker volume create [name of volume]
作成された Volume は以下のようにタイプすることで確認できます:
docker volume ls

% docker volume ls
DRIVER              VOLUME NAME

これで、僕らが持っている他の Volume をリストできます。Volume は使っている間にたくさんになってしまいがちですので、数を減らすやり方を知っていると良いでしょう。次のようにタイプします:
docker volume prune
これで今使っていない Volume を削除できます。続けて良いかどうか確認がはいります。

% docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] 

もし、単体の Volume を削除したい場合は、次のようにタイプします:
docker volume rm [name of volume]
君が知りたいだろうもう一つのコマンドは、作った Volume をより詳細に見ることのできる inspect コマンドです。恐らく、永続化ファイルに関する話題としては、もっとも重要です。
docker inspect [name of volume]
これについてのコメントは、Docker が配置するこれらファイルについてほとんど気にしないかも知れませんが、デバッグ目的で時々知りたくなるはずです。このセクションの後で示すように、アプリケーションの開発時に永続化ファイルをコントロールすることは、僕らのアドバンテージとして機能します。

% docker inspect logs
[
    {
        "CreatedAt": "2020-05-16T10:18:25Z",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/logs/_data",
        "Name": "logs",
        "Options": null,
        "Scope": "local"
    }
]

Moutpoint フィールドは、Docker が永続化ファイルにしようとしている場所を教えてくれます。

アプリケーションに Volume をマウントする

OK、それでは、アプリケーションで使いたい Volume の要点に触れました。僕らのコンテナーにあるファイルを変更したり作成したりしたいので、コンテナーを終了して再起動しても、変更はそのまま残ります。
これを行うために、ほとんど同じことをするための二つの異なるコマンド・構文を使えます。それは:

  • -v、--volume、構文は -v [name of volume]:[directory in the container] となります。例えば、-v my-volume:/app
  • --mount、構文は --mount source=[name of volume],target=[diretory in container]、例えば、--mount source=my-volume,target=/app

コンテナの実行と組み合わせると、次のようになります:
docker run -d -p 8000:3000 --name my-container --volume myvolume:/logs chrisnoring/node

試してみましょう。まず初めにコンテナを実行します:

% docker run -d -p 8000:3000 --name my-container --volume logs:/logs chrisnoring/node
db2e45b88f88f67633c20e55907770b84d342c5e2377df531bf990522bb0bcc8

訳注
もし、すでにコンテナーが存在している状態の場合はエラーになりますので、docker ps -a などとして、実行しているコンテナーを確認し、docker stop my-container docker rm my-container して、コンテナーを削除してください。

それでは、コンテナーの内部に Volume がマウントされているかどうか、inspect コマンドを実行してみましょう。

        ・・・
        },
        "Mounts": [
            {
                "Type": "volume",
                "Name": "logs",
                "Source": "/var/lib/docker/volumes/logs/_data",
                "Destination": "/logs",
                "Driver": "local",
                "Mode": "z",
                "RW": true,
                "Propagation": ""
            }
        ],
        "Config": {
        ・・・

訳注
inspect コマンドの実行ですが、ここでは、docker inspect my-container のことを言っているようです。このようにすることで、my-container コンテナーの状態全体が JSON で返ってきますので、そのうちの "Mounts" の内容を確認します。

OK、僕らの Volume がありますね。良いでしょう。次のステップは、コンテナーの中の Volume を配置することです。コンテナーに入っていきましょう:
docker exec -it my-container bash
そして、/logs ディレクトリを確認します:

% docker exec -it my-container bash
root@db2e45b88f88:/app# cd ..
root@db2e45b88f88:/# ls
app  bin  boot  dev  etc  home  lib  lib64  logs  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@db2e45b88f88:/# cd logs/
root@db2e45b88f88:/logs# echo logging... > logs.txt
root@db2e45b88f88:/logs# ls
logs.txt
root@db2e45b88f88:/logs# 

OK、今、もしコンテナーを終了したなら、Volume に作ったすべては永続化されて、Volume にないものはすべて失われるはず。うん、いいアイディア。良いでしょう、Volume の原理を理解しましょう。

訳注
一旦、docker stop my-container docker rm my-container して、コンテナーを削除しても、docker volume ls すると Volume が残っていることが分かります。その上で、また docker run (略) --volume logs:/logs (略)docker exec -it my-container bash して中に入れば、/logs フォルダに logs.txt が残っていることが確認できるでしょう。

Volume をサブディレクトリとしてマウントする

ここまで、Volume を作って、Docker に永続化するファイルの場所を設定しました。それらのファイルを永続化すると設定したとき、何が起きているのでしょう?

もし、ハード ドライブのディレクトリをポイントすると、そのディレクトリが見えたり、ファイルを配置することができるだけでなく、すでにあるファイルをコンテナーのマウント ポイントに持ってくることもできます。それではデモしていきましょう。私が言っているのは:

  • ディレクトリの作成 /logs ディレクトリを作りましょう
  • ファイルを作成する logs.txt ファイルを作り、そこにテキストを書きましょう
  • コンテナーを実行しましょう ローカル ディレクトリ + /logs をマウント ポイントとして作成しましょう

最初の二つのコマンドで、こんな風なファイル構造になるでしょう。(訳注:Node.js プロジェクトのフォルダ内です)

app.js
Dockerfile
/logs
 logs.txt // contains 'logging host...'
package.json
package-lock.json

さて、次は run コマンドを実行して、コンテナーを立ち上げましょう:

% docker run -d -p 8000:3000 --name my-container --volume $(pwd)/logs:/logs chrisnoring/node
186c05ced5e02c4a84996f4b55717e08633c0f8f0b228674ef9f0cb3ecb15f35

訳注
例によって、すでにコンテナーが存在している状態の場合はエラーになりますので、docker ps -a などとして、実行しているコンテナーを確認し、docker stop my-container docker rm my-container して、コンテナーを削除してください。

なお、Windows では $(pwd)/logs がエラーとなります。代わりに、PowerShell から以下のようにしてください。
docker run -d -p 8000:3000 --name my-container -v "${pwd}/logs:/logs" chrisnoring/node

--volume コマンドが少し異なりますね。最初のパラメータ $(pwd)/logs は、カレント ディレクトリとそのサブ ディレクトリ logs を意味しています。二つ目のパラメータ /logs は、僕らのホスト コンピューターの logs ディレクトリーをコンテナーの同じ名前のディレクトリにマウントすることを意味しています。
コンテナーにダイブして、コンテナーが僕らのホスト コンピュータにある logs ディレクトリからのファイルを実際に持ってきていることを確認しましょう。

% docker exec -it my-container bash
root@186c05ced5e0:/app# ls
Dockerfile  app.js  node_modules  package-lock.json  package.json
root@186c05ced5e0:/app# cd ..
root@186c05ced5e0:/# ls
app  bin  boot  dev  etc  home  lib  lib64  logs  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
root@186c05ced5e0:/# cd logs/
root@186c05ced5e0:/logs# ls
logs.txt
root@186c05ced5e0:/logs# cat logs.txt
logging host...
root@186c05ced5e0:/logs#

上記通りのコマンド セットで docker exec -it my-container bash コンテナーに入り、logs ディレクトリーに進み、ついに、cat logs.txt で logs.txt を読み出しました。結果は logging host... これは一つの例で、僕らがホスト コンピューターで持っているファイルと内容は正確に同じです。

これは ホスト コンピューターの Volume とコンテナーの間を接続している Volume です。ホスト コンピューターの log.txt を編集して、コンテナーに何が起きるか確認してみましょう。

root@186c05ced5e0:/logs# cat logs.txt
logging host 2...

わぉ、コンテナーを終了したり、再起動したりせずに、コンテナーの中を変更しました。

アプリケーションを Volume として扱う

アプリを Volume として扱うように作るために、コンテナーをこんな風に終了させます。
docker kill my-container && docker rm my-container
なぜこんなことをする必要があるのでしょう?それは、ソースコードだけでなく Dockerfile も変更しようとしていて、以下に示そうとしているように Volume を使わない限り、コンテナーは変更を反映できないからです。

今回は、Volume の名前を --volume $(pwd):/app とパラメータで変えてコンテナーを再実行する必要があります。(訳注:Windows + PowerShell の場合は --volume "${pwd}:/app" となります)

注:
もし、PWDがスペースを含むディレクトリで構成されている場合は、"$(PWD)":/app を代わりにパラメータとして指定してください。つまり、$(PWD) をダブルクォーテーション「"」で囲む必要があります。指摘してくれた Vitaly に感謝します:grinning:

完全なコマンドは以下のようになります(訳注:Node.js プロジェクトのフォルダで行います):

% docker run -d -p 8000:3000 --name my-container --volume $(pwd):/app chrisnoring/node
1b4019ec7c4379f7943a5a1e5a9f3e397cbf81a85060d64e9684e8760867802b

これによって、僕らのアプリ ディレクトリを Volume にして、コンテナー内の何か変更を反映するようにします。

では、Node.js Express アプリケーションにルートを追加しましょう:

app.get("/docker", (req, res) => {

  res.send("hello from docker");

});

OK、Express ライブラリを扱うことで知っていることから、ブラウザーから http://localhost:800/docker は到達できるかな?

Cannot GET /docker

悲しい顔だね:frowning: 動いていません。何が良くなかったのでしょう?まぁ、こういうことです。Node.js Express アプリケーションのソースコードを変更した場合、アプリをリスタートする必要があります。戻って、ファイル変更に対して即座に Node.js Express ウェブ サーバーを再起動する方法を考えなければなりません。それにはいくつかのやり方があります。例えば:

  • インストール ウェブ サーバーをリスタートする nodemon や forever のようなライブラリをインストール
  • 実行 PKILL コマンドを実行して、node.js プロセスを kill し、node app.js を実行する

nodemon のようなライブラリをインストールするだけなら、面倒ということもないので、さっそくそうしましょう(訳注:プロジェクトのフォルダで実行してください):

npm install --save-dev nodemon

これは、他のライブラリの依存関係を pckage.json に持ったということですが、アプリを動かす方法を変える必要があるということでもあります。アプリは nodemon app.js と言うコマンドを使ってスタートさせなければなりません。これは nodemon が、変更あり次第、全体をリスタートするようケアすることを意味します。それでは、start script を package.json に追加しましょう。結局、それは Node.js 的な方法です:

start:nodemon app.js

Node.js が初めての人のためにも、上でおこなったことを書こう。start script を package.json に追加するっていうのは、"scripts" セクションに行き、次のように entry start を追加します(package.json の抜粋):

package.json
"scripts": {
  "start": "nodemon app.js"
}

デフォルトでは、"scripts" にあるコマンドは、npm run [name of command] と入力して実行します。しかし、 start や test といった知られたコマンドは、キーワード run で省略でき、npm run startnpm start と書けます。他のコマンド "log" を追加してみましょう(package.json の抜粋):

package.json
"scripts": {
  "start": "nodemon app.js",
  "log": "echo \"Logging something to screen\""
}

新しいコマンド "log" を実行するのに、npm run log と書けます。

OK、一つ残っていますが、それは、Dockerfile を僕らのアプリをどう start するか変更することです。最後のラインを:

Dockerfile
ENTRYPOINT ["node", "app.js"]

こうします:

Dockerfile
ENTRYPOINT ["npm", "start"]

Dockerfile を変更したので、イメージをリビルドします。このようにします:
docker build -t chrisnoring/node .

訳注
しつこいようですが、docker stop my-container docker rm my-container をお忘れなく。コンテナーが残っている時に、新たにイメージを作ると、古いイメージが実行中のコンテナー用に無名のイメージとして残ります。必要に応じて、docker images で確認し、docker rmi <image id> などとして削除した方がよいでしょう。

OK、次のステップはコンテナーの起動です:
docker run -d -p 8000:3000 --name my-container --volume $(PWD):/app chrisnoring/node
注目に値することは、カレントとなるプロジェクト ディレクトリ全体を公開し、それをコンテナ内の /app にマッピングする方法です。

/docker に対するルートはすでに追加したので、次のように新しいルートを追加してみましょう。

app.get('/nodemon', (req, res) => res.send('hello from nodemon'))

僕らが app.js の変更を保存したとき、nodemon がその変更を反映してくれますように!

hello from nodemon

アァァァァンド、僕らは勝った!/nodemon がルートとして動いている。僕は君を知らないけど、これを最初に機能させたのは僕ってことだ。(訳注:ちょっと意味不明・・)

We have a winner

サマリー

これで記事の最後まで到達しました。とてもクールで使いやすい機能である Volume について学びました。更に重要なことは、全ての開発環境を Volume にして、ソースコードをコンテナーのリスタートなしに働かせ続けられるようにしたことです。

僕らのシリーズのパート3では、リンクされたコンテナーやデータベースがどのように動くかについてカバーします。乞うご期待。

Twitter をフォローして、トピックへのあなたの問い合わせやご質問、提案を頂けるとハッピーです。

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

Dockerで環境構築したローカルサイトにSSL証明書エラーでアクセスできなかった時の対処法

DockerとPHP Laravelを使用し環境構築を行った際、
$ docker-compose up -d でコンテナを立ち上げたあと、
ローカルサイトにhttpsアクセスすると証明書エラーが出てアクセスができない…

SSLサーバ証明書発行したはずなんだけど…と思ってたら、
自己証明書は、基本的にブラウザに信頼されないため、信頼する証明書として手動で追加する必要がある
とのこと。知らんかった。

ということで、
1. SSL証明書を発行する手順
2. macOSで信頼する証明書として追加する手順

の備忘録。

発生したエラー

参考までに、発生したエラー

この接続ではプライバシーが保護されません
NET::ERR_CERT_INVALID

スクリーンショット 2020-05-15 11.58.03.png

1. SSL証明書を発行する

 #nginxコンテナに入る
$ docker-compose exec nginx sh
 #apkアップデートとOpenSSLのパッケージのインストール
$ apk add --update openssl
 #server.keyという名前で 2048bit の秘密鍵を作成
$ openssl genrsa 2048 > server.key
 #秘密鍵から署名要求(server.csr)を作成
$ openssl req -new -key server.key > server.csr
C=JP/ST=Tokyo/L=minato-ku/O=Example/OU=Web/CN=Exampledomain
 #署名要求を秘密鍵で署名してサーバ証明書(server.crt)を作成
$ openssl x509 -days 3650 -req -signkey ./server.key -in server.csr -out ./server.crt

基本的なSSL証明書の発行は以上でOK。

なんかChromeの仕様変更により、ドメイン名のチェックをCommon Name(通称CN)ではなく
Subject Alternative Names(通称SAN)を参照するようになったという記事を見つけたため、
もしSubject Alternative Namesを含んだ自己署名サーバ証明書を作成する場合は以下。

 #SANの設定値を定義するtxtファイルを用意(ファイル名は任意) 
$ touch san.txt
san.txt
subjectAltName = DNS:Exampledomain, IP:127.0.0.1 

SANの定義ファイルを用意したら、秘密鍵・証明要求を作成するところまでは先述した手順と同じ。
サーバ証明書を作成する際に-extfileオプションでSANの定義ファイルを読み込ませる。

 #用意した定義ファイルを読み込ませてサーバ証明書を作成
$ openssl x509 -days 3650 -req -extfile san.txt -signkey server.key < server.csr > server.crt

 #作成したサーバ証明書の内容を確認する
$ openssl x509 -in server.crt -text -noout
Certificate:
     …
        Subject: C = JP, ST = Tokyo, L = minato-ku, O = Example, OU = Web, CN = Exampledomain
        Subject Public Key Info:
     …
        X509v3 extensions:
            X509v3 Subject Alternative Name: 
                DNS:Exampledomain, IP Address:127.0.0.1

サーバ証明書の内容を確認してCommon NameとSubject Alternative Namesが出力されていればOK。

2. 作成したサーバ証明書を信頼する証明書として追加する手順[macOS]

1.で作成したサーバ証明書(server.crt)を 信頼する証明書として設定すれば、 HTTPS の通信ができるようになる。

下記の手順で設定します。詳しくはこちらの記事を参照。

  • キーチェーンアクセス.appを開く
  • 作成したserver.crtをダブルクリックで開く
  • 証明書の詳細画面で「信頼」を開く
  • 「この証明書を使用するとき」項目を常に信頼に変更

以上の手順を踏んでローカルサイトにアクセスすると、入れるようになった…!!!
手順的にはさほど難しくないけど、ど素人からすると解決まで長い道のりだった( ; ; )

参考サイト

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

Dockerにsshdをインストールしてsshログインする

目的

Dockerにsshdをインストールする方法に関する備忘録です

少し探したところ、公式サイトに書いていた、、

Dockerize an SSH service

Dockerfileを作成して起動

Dockerfileを作成する

Dockerfile
FROM ubuntu:16.04

RUN apt-get update && apt-get install -y openssh-server
RUN mkdir /var/run/sshd
RUN echo 'root:THEPASSWORDYOUCREATED' | chpasswd
RUN sed -i 's/PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config

# SSH login fix. Otherwise user is kicked off after login
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd

ENV NOTVISIBLE "in users profile"
RUN echo "export VISIBLE=now" >> /etc/profile

EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]

Dockerfileと同じディレクトリでdocker buildする

$ docker build -t eg_sshd .
...
Successfully built a25d2079f336
Successfully tagged eg_sshd:latest
$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
eg_sshd             latest              a25d2079f336        2 minutes ago       205MB

buildに成功したのでdocker runする

$ docker run -d -P --name test_sshd eg_sshd
2c72816dcfccbe6ed82e15635d4a43d77180b564a95de32c553bfe8c5e49fb16
$ docker ps
CONTAINER ID        IMAGE                    COMMAND               CREATED             STATUS              PORTS                   NAMES
2c72816dcfcc        eg_sshd                  "/usr/sbin/sshd -D"   21 seconds ago      Up 20 seconds       0.0.0.0:32768->22/tcp   test_sshd

dockerコンテナの22番ポートがどこにマッピングされているか確認する(今回は32768のようだった)

$ docker port test_sshd 22
0.0.0.0:32768

IPアドレスか、localhostを指定してsshでログインする

$ ssh root@localhost -p 32768
root@localhost's password:(Dockerfileでchpasswdした値、例:"THEPASSWORDYOUCREATED")
Welcome to Ubuntu 16.04.6 LTS (GNU/Linux 4.9.125-linuxkit x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

root@2c72816dcfcc:~# 

sshでdockerコンテナ内にログインできました。

参考

Dockerize an SSH service
DockerでポータブルなLinux開発環境(GUI付き)を構築する

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

Dockerへvnc接続する

目的

Dockerへvnc接続した際の備忘録です

Dockerhub上のイメージを確認

以下を参考にさせて頂きます

queeno/ubuntu-desktop
Ubuntu Desktop Dockerfile
Docker container for Ubuntu 16.04 including ubuntu-desktop and vncserver.

Dockerhub上のイメージを起動してvnc接続

docker runします

docker run -p 5901:5901 queeno/ubuntu-desktop
...
16/05/20 15:06:31 Protocol versions supported: 3.3, 3.7, 3.8, 3.7t, 3.8t
16/05/20 15:06:31 Listening for VNC connections on TCP port 5901
...

その後、vnc接続します

vnc://:5901 via VNC client.
The VNC password is password.

Macの場合は、finder→移動→サーバへ接続→vnc://localhost:5901 へ接続する
スクリーンショット 2020-05-16 23.36.02.png
スクリーンショット 2020-05-16 23.36.12.png

接続できました

スクリーンショット 2020-05-16 23.36.41.png

xeyesコマンドで目を出せました

スクリーンショット 2020-05-16 23.37.21.png

Dockerfileからbuildしてコンテナ起動する

起動したdockerイメージのDockerfileは以下のようです

queeno/docker-ubuntu-desktop

git cloneで取得する

$ git clone https://github.com/queeno/docker-ubuntu-desktop
$ cd docker-ubuntu-desktop

Dockerfileを確認する

Dockerfile
FROM ubuntu:16.04

ENV DEBIAN_FRONTEND noninteractive
ENV USER root

RUN apt-get update && \
    apt-get install -y --no-install-recommends ubuntu-desktop && \
    apt-get install -y gnome-panel gnome-settings-daemon metacity nautilus gnome-terminal && \
    apt-get install -y tightvncserver && \
    mkdir /root/.vnc

ADD xstartup /root/.vnc/xstartup
ADD passwd /root/.vnc/passwd

RUN chmod 600 /root/.vnc/passwd

CMD /usr/bin/vncserver :1 -geometry 1280x800 -depth 24 && tail -f /root/.vnc/*:1.log

EXPOSE 5901

コマンドラインから実行するのは煩わしいのでdocker-compose.ymlを用意

docker-compose.yml
version: '3.3'
services:
    test:
        build:
          context: .
          dockerfile: Dockerfile
        container_name: ubuntu1604-desktop-test
        image: 'ubuntu1604-desktop-test:latest'
        ports:
          - 5901:5901
        stdin_open: true

その後、docker build & docker run を実行する

$ docker-compose build
$ docker-compose run
...
ubuntu1604-desktop-test | 16/05/20 15:35:50 Protocol versions supported: 3.3, 3.7, 3.8, 3.7t, 3.8t
ubuntu1604-desktop-test | 16/05/20 15:35:50 Listening for VNC connections on TCP port 5901
...

再び、vnc接続してログインできる事を確認

vnc://:5901 via VNC client.

スクリーンショット 2020-05-17 0.42.17.png

参考

dockerで手軽にLinuxデスクトップ環境を試せる!
queeno/ubuntu-desktop
queeno/docker-ubuntu-desktop

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

シンプルなDockerの起動と停止方法

Dockerの起動と停止

Dockerの起動と停止方法について必要な情報だけをまとめたシンプルな内容を作成しました。

関連するコンテナをまとめて起動

$ docker-compose start

関連するコンテナをまとめて停止

$ docker-compose stop

この状態でPCをシャットダウンすることができます。

ちなみに...

停止してすぐに再起動をしたい場合はリスタートがおすすめです!

$ docker-compose restart

お勧めできない停止方法

下記のコマンドは安易に行わないようにしましょう。

$ docker-compose down

こちらのコマンド実行するとインストールしたはずのGemがなくなってしまうようなことがありますので注意が必要です。

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