20200710のdockerに関する記事は13件です。

DockerのVolumeについて

EC2(AmazonLinux2)環境にてDockerと戯れているのですが、
気がついたらホストOS上にマウントポイントが増殖していました。。。
そこでVolumeの理解を深める為に色々と試しました。

DockerにおけるVOLUMEについて

Dockerリファレンスのdockerfile-VOLUMEの説明より抜粋

VOLUME 命令は指定した名前でマウントポイントを作成し、他のホストやコンテナから外部マウント可能なボリュームにします。
docker run コマンドは、ベース・イメージから指定した場所に、データを保存する場所として新規作成したボリュームを初期化します。

これを読んで「コンテナ内にVOLUMEで指定したディレクトリが作成されるんだな」と理解はしましたが、"他のホストやコンテナから外部マウント可能なボリュームにします"という部分は、
コンテナ起動時(run)に-vでホストOS上のディレクトリとの紐付けを可能にするディレクトリを定義するという認識でした。(-vを指定しないと結局のところ永続化はされずデータは破棄される認識)

で、色々とVolumeの動作検証をしました。

検証環境

  • EC2 (Amazon Linux2)

動作検証

  • VOLUME指定の無いイメージ(CentOS)からコンテナ起動してみる(-v, --mount指定なし)
#Volumeは存在しない(コンテナ起動前)
[~]docker volume ls
DRIVER              VOLUME NAME

#CentOSイメージからコンテナ起動
[~]docker run --name test_container -dt centos

#Volumeは存在しない(コンテナ起動後)
docker volume ls
DRIVER              VOLUME NAME
  • VOLUME指定のあるイメージからコンテナ起動してみる(-v, --mount指定なし)
    下記dockerfileを使用してCentOSイメージをベースにVolume指定されたイメージを作成して起動してみる
#dockerfile(CentOSイメージをベースにVolume=/test_volumeを定義)
ARG baseimagetag=latest
FROM centos:${baseimagetag} AS baseimage
VOLUME /test_volume

#dockerイメージ作成
[~]docker build -t centos_mod .

#Volumeは存在しない(コンテナ起動前)
[~]docker volume ls
DRIVER              VOLUME NAME

#CentOS(改変)イメージからコンテナ起動
[~]docker run --name test_container -dt centos_mod

#Volumeが作成される(コンテナ起動後)
docker volume ls
DRIVER              VOLUME NAME
local               ec1feead17bb87e24d3e2e6db716daf58d12747cbdd0b510fd30f507d7f8308b

#VolumeのホストOS上のマウントポイントを確認
#自動的に/var/lib/docker/volumes/配下にマウントポイントが作成されていることがわかる
[~]docker inspect ec1feead17bb87e24d3e2e6db716daf58d12747cbdd0b510fd30f507d7f8308b
[
    {
        "CreatedAt": "2020-07-10T08:30:00+09:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/ec1feead17bb87e24d3e2e6db716daf58d12747cbdd0b510fd30f507d7f8308b/_data",
        "Name": "ec1feead17bb87e24d3e2e6db716daf58d12747cbdd0b510fd30f507d7f8308b",
        "Options": null,
        "Scope": "local"
    }
]

#コンテナ停止、削除
[~]docker stop test_container
[~]docker rm test_container

#Volumeが確認(コンテナ削除後)
#ホストOS上のマウントポイントは存在している
docker volume ls
DRIVER              VOLUME NAME
local               ec1feead17bb87e24d3e2e6db716daf58d12747cbdd0b510fd30f507d7f8308b
  • VOLUME指定のあるイメージからコンテナ起動してみる(-v にてVolume名を指定)
#CentOS(改変)イメージからコンテナ起動(ホストOSのマウントポイントを名称(host_mount)で指定
[~]docker run --name test_container -v host_mount:/test_volume -dt centos_mod
baf6954e9dbce1dd9ad3ae5c8286e63c01fd39689d79053725ae1800b70ea752

#Volumeが作成される(コンテナ起動後)
[~]docker volume ls
DRIVER              VOLUME NAME
local               host_mount

#VolumeのホストOS上のマウントポイントを確認
#自動的に/var/lib/docker/volumes/配下に-vで指定した名前/_dataでマウントポイントが作成されていることがわかる
docker inspect host_mount
[
    {
        "CreatedAt": "2020-07-10T22:22:49+09:00",
        "Driver": "local",
        "Labels": null,
        "Mountpoint": "/var/lib/docker/volumes/host_mount/_data",
        "Name": "host_mount",
        "Options": null,
        "Scope": "local"
    }
]
  • VOLUME指定のあるイメージからコンテナ起動してみる(-v にてホストOS上のディレクトリを指定)
#CentOS(改変)イメージからコンテナ起動(ホストOSのマウントポイントをディレクトリ(/test_mount)で指定
[~]docker run --name test_container -v /test_mount:/test_volume -dt centos_mod
e5e70d6235dbfe54950e2053f61236c1450d43c0b3aacfa38341e37cfacecaaa

#Volumeの確認(コンテナ起動後)
#下記コマンドではマウントポイントは表示されない
[~]docker volume ls
DRIVER              VOLUME NAME

#コンテナ情報からマウントポイントを確認
[~]docker inspect test_container
##一部抜粋
        "Mounts": [
            {
                "Type": "bind",
                "Source": "/test_mount",
                "Destination": "/test_volume",
                "Mode": "",
                "RW": true,
                "Propagation": "rprivate"
            }
        ],

動作検証をして理解したこと

  • VOLUMEが定義されたDockerイメージを使用してコンテナ起動すると、 VOLUMEで指定されたディレクトリが永続化領域としてコンテナ内に作成される
  • Dockerコンテナ起動時(run)にVOLUMEで指定されたディレクトリに対応するホストOS上のマウントポイント(ディレクトリ)を指定しない場合、ホストOS上のDockerのVolume領域(上記検証では/var/lib/docker/volumes)にマウントポイントが自動で作成される
  • 起動時にVOLUMEで指定されたディレクトリに対応するホストOS上のマウントポイント(名称)を指定した場合、無指定時と同様、ホストOS上のDockerのVolume領域にマウントポイントが指定した名称/_dataで作成される
  • docker volume lsで表示されるマウントポイントはホストOS上のDockerのVolume領域(/var/lib/docker/volumes)に作成されたディレクトリを表示している
    ※Volume領域以外のディレクトリをマウントポイントに指定した場合は表示されない
  • ホストOS上に作成されたマウントポイントはコンテナを停止、破棄しても削除されない(永続化領域なんだから当たり前)
    ※VOLUME指定されたイメージ(MySQLなど)からのコンテナ起動を繰り返していると認識していないディレクトリが山のように発生している可能性も。。)

(おまけ)Volume指定されているイメージかを確認する方法

docker inspect <イメージ名>でイメージの情報を表示し、"Volumes": の部分にディレクトリが指定されてるかを確認する

例)MySQLコンテナの場合
永続化領域としてコンテナ内に/var/lib/mysqlが定義されている

"Volumes": {
        "/var/lib/mysql": {}
},
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DockerでNuxt.jsプロジェクト新規作成セット

概要

  • nuxt.jsのセットアップ、新規プロジェクト作成、サーバー起動までをかんたん手順で行えます。
  • Dockerコンテナとして構築するので、お手元のPCを汚しません。
  • 複製、破棄、構築し直しも、手軽に行えます。

github(一式ダウンロード)

https://github.com/yagrush/docker-nuxtjs

必要なもの

  • Docker
  • docker-compose
  • makeコマンド

がインストールされている Mac / Linux。
(WindowsではnodeのDockerコンテナが起動しませんでした。要調査。)

使い方

https://github.com/yagrush/docker-nuxtjs のリポジトリをcloneまたはダウンロード&解凍する。

以下の2つのファイルを編集する。

.env

PROJECT_NAMEの値をご自分の希望に合わせて編集してください。
この値は、nuxt.jsプロジェクトのディレクトリ名にもなります。

PROJECT_NAME=my_project

Makefile

Makefileは、makeコマンド用の設定ファイルです。
これを使うと、複数のコマンド操作に名前を付けて、ショートカットのように簡単に呼び出せます。

さて、最近のバージョンでは、create-nuxt-app(nuxt.jsプロジェクト作成コマンド)実行時、途中でカスタム内容の指定を求められます。
本一式ではその入力を自動化するために create-nuxt-app実行時のオプション --answers で予めカスタム内容を指定するようにしています。

カスタム項目一覧はこちらの公式ソースコードからご確認いただけます。
nuxt.js公式リポジトリ内、prompts.js
--answers のパラメータをJSON形式で指定して、ご自分のご希望に合わせて下さい。

...
...
create-nuxt-app:
    docker-compose exec dev bash -c 'create-nuxt-app $$PROJECT_NAME --answers "{ \
    \"name\": \"$$PROJECT_NAME\", \
    \"language\": \"js\", \
    \"pm\": \"yarn\", \
    \"ui\": \"vuetify\", \
    \"features\": [\"axios\"], \
    \"linter\": [\"eslint\"], \
    \"test\"  : \"jest\", \
    \"mode\"  : \"universal\", \
    \"target\"  : \"static\", \
    \"devTools\": [\"jsconfig.json\"] }" \
    '
...
...

※ エスケープが若干複雑ですみません。
Makefile > docker-compose > bash -c と入れ子になっているので…
基本的にサンプルをコピペ&編集して頂ければ大丈夫かとは思います。
(サンプルの設定は、単なる私の好みです。)

コマンドインターフェースを起動する。

ダウンロードしたフォルダの中に移動する。

# git cloneした場合
cd docker-nuxtjs

# ZIPをダウンロードして解凍した場合
cd docker-nuxtjs-master

以下のコマンドを実行する。

make init

成功すると、このようなコマンドログになります。↓

...
...
yarn run v1.22.4
$ eslint --ext .js,.vue --ignore-path .gitignore . --fix
Done in 24.57s.

?  Successfully created project my_project

  To get started:

    cd my_project
    yarn dev

  To build & start for production:

    cd my_project
    yarn build
    yarn start

  To test:

    cd my_project
    yarn test

docker-compose exec dev bash -c 'sed -i -e "s@export default {@export default {\n  telemetry: false,\n@g" $PROJECT_NAME/nuxt.config.js'
docker-compose exec -d dev bash -c 'cd $PROJECT_NAME && npm run dev'

$

ちょっぴり解説コーナー

docker-compose exec dev bash -c 'sed -i -e "s@export default {@export default {\n  telemetry: false,\n@g" $PROJECT_NAME/nuxt.config.js'

nuxt.config.jsのexport default節に telemetry: false を追記します。
これにより、最近npm run dev実行時に「サービス向上のため情報送信に協力するか?」の回答入力を要求されてしまうのを自動的に回避(falseだと拒否)します。

Nuxt.jsサンプルページが起動しているはずなのでアクセスしてみる。

image.png

↑ こんなページ、見れましたでしょうか?
見れたら成功です。

本リポジトリ内のapp/(make initすれば生成されます)とdockerコンテナ内の/work/appが同期(ボリュームマウント)しているので、例えばapp/$PROJECT_NAME/pages/index.vueを編集すれば、即座に↑のサンプルページに反映されます。

Dockerコンテナを停止する

make stop

Dockerコンテナを起動する

make up

Dockerコンテナを再ビルドする

make remake

※ Nuxt.jsプロジェクトの再作成はしません。Dockerコンテナとしての再ビルドです。

本一式を完全廃棄する

make destroy

※ このコマンドだけではapp/や本一式の内容物をいきなり削除はしないのでご安心ください。

そのあと、ご自身の手で本一式のディレクトリを削除してください。

あとがき

js界隈は変化が速過ぎて、WEB文献そのままでは全然動かず苦労します。
これを流用して少しでもショートカットして、みなさんのコーディング時間確保などに役立てれば幸いです。

また、nginxで動かすproduction版など改善の余地がまだまだあるので、時間あるときにまた更新していきます。

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

CircleCIを使ってGitのコミットごとにGCPにDockerイメージを作る

はじめに

コミットごとにDokerのイメージを作るようにしました。

それぞれのコミットごとに完全動作するコンテナが出来上がります。

こうしておくと

  1. CIの一つとしてイメージのビルドが通る、イメージを使ってテストを実行できる、といったことが可能になる
  2. それぞれのイメージでデプロイができる
  3. 検証をする場合にイメージのビルドを行わず、プルすることができる

といったメリットがあります。

Dockerfileの準備

テスト用に Dockerfile を作成しておきます。

Dockerfile
FROM golang:latest

テスト用なのでどういったDockerfileでも構いません。

設定

CircleCIの設定

CircleCIでGCPを使う場合の参考ページです
https://circleci.com/docs/2.0/google-auth/

基本的にこのページに沿っていけば実現できるのですが、うまく動かないポイントも多いため注意が必要です。

まずCircleCIでAdd Projectし、GitHub(やGitLab, Bitbucket)と連携しておきます。
(GitHubとCircleCIの連携は済ませているとします)

Screen Shot 2020-07-10 at 16.43.35.png

GCPでのサービスアカウントの登録

GCP上でサービスアカウントを登録します。

Screen Shot 2020-07-10 at 16.45.38.png

作成したサービスアカウントからキーをJSONでダウンロードしておきます。

Screen Shot 2020-07-10 at 16.46.00.png

image.png

次に「IAM」から作成したサービスアカウントに対して権限を付与します。

権限
Cloud Build サービス アカウント
Storage オブジェクト管理者
Storage オブジェクト作成者
Storage オブジェクト閲覧者
閲覧者

Screen Shot 2020-07-10 at 16.48.02.png

Cloud Buildを実行するための権限、CGRにイメージをアップロードするためのCloud Storage関連の権限、プロジェクトを参照するための閲覧権限が必要でした。

思った以上に権限が必要で、足りないと途中でエラーが出るためその対処は大変です。
CircleCIによるGCPの参考ページにもGCRの場合には追加の権限が必要になる、との記載があります。

If you are having issues pushing container images to GCR you may need more granular permissions than the default service account provides. You can grant permission changes in the Cloud Storage IAM Console
https://circleci.com/docs/2.0/google-auth/

「プロジェクトの編集者」といった権限を与えるとなんでもできてしまうため権限が足りなエラーは解消しますが、自動化する場合には万が一の漏洩を考えて最小限の権限とすることが必要です。

ローカルでの試験

CircleCIでの手順に進む前にローカル環境から正しく動くか、権限が足りているか、ということを確認しておきます。
こうすることでCircleCI、GCPといった複数のサービスをまたがって行う作業に対してトラブルを早めに見つけられるようにしておきます。

まずプロジェクトIDとリージョン(ゾーン)を設定しておきます。(プロジェクト名をexampleとしていますが適宜読み替えてください)

$ export GOOGLE_PROJECT_ID=example
$ export GOOGLE_COMPUTE_ZONE=ap-northeast1

先ほどダウンロードしたCircleCI用のキーでgcloudコマンドで認証を掛けます。

$ echo <ダウンロードしたキーの場所>  | gcloud auth activate-service-account --key-file=-

Activated service account credentials for: [circleci@example.iam.gserviceaccount.com]

プロジェクトとリージョンの設定を行います。

$ gcloud --quiet config set project ${GOOGLE_PROJECT_ID}
$ gcloud --quiet config set compute/zone ${GOOGLE_COMPUTE_ZONE}

アカウントが切り替わっていることを確認しておきます。

$ gcloud config list

[compute]
zone = ap-northeast1
[core]
account = circleci@example.iam.gserviceaccount.com
disable_usage_reporting = False
project = example

Your active configuration is: [default]

先ほど作成したDockerfileをビルドしてみます。

$ gcloud builds submit --tag gcr.io/${GOOGLE_PROJECT_ID}/test .


Creating temporary tarball archive of 10 file(s) totalling 5.4 KiB before compression.
Uploading tarball of [.] to [gs://example_cloudbuild/source/1594367971.xxxxxxxxxxxxxxxx.tgz]
Created [https://cloudbuild.googleapis.com/v1/projects/xxxxxxxxxxxxxxxxxxxxxx].
.....


latest: digest: sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx size: 1795
DONE
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

ID                                    CREATE_TIME                DURATION  SOURCE                                                                                            IMAGES                                    STATUS
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx  2020-07-10T07:59:32+00:00  18S       gs://example_cloudbuild/source/1594367971.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.tgz  gcr.io/example/test (+1 more)  SUCCESS

成功しました。

確認しておきます。

$ gcloud container images list-tags gcr.io/example/test

DIGEST        TAGS                                    TIMESTAMP
b413792axxxx  latest                                  2020-07-07T18:20:07

正しく作成されていますね。

CircleCIへの組み込み

CircleCIでビルドが通るように設定を行います。

環境変数を設定します。

CircleCIのプロジェクトを開いた画面中にある Project Settings から Environment Variables を選択します。

image.png

それぞれの変数を設定しています。
鍵のJSONについては pbcopy などを利用すると便利です。

$ cat ~/Download/example.json | pbcopy
環境変数名
GCLOUD_SERVICE_KEY 先の手順で作成したサービスアカウントの
GOOGLE_PROJECT_ID プロジェクトID
GOOGLE_COMPUTE_ZONE コンピュートゾーン (ap-northeast1 ap-northeast2 など)

下記のように3つの変数を設定します。

image.png

セットアップ

次にCircleCIの config.yml を設定します。

CircleCIではgoogle/cloud-sdkというイメージを使うとgcloudが一通り揃っています。

circleci/config.yml
version: 2.1
jobs:
  build:
    docker:
      - image: google/cloud-sdk
    steps:
      - checkout
      - run: |
          echo $GCLOUD_SERVICE_KEY | gcloud auth activate-service-account --key-file=-
          gcloud --quiet config set project ${GOOGLE_PROJECT_ID}
          gcloud --quiet config set compute/zone ${GOOGLE_COMPUTE_ZONE}
          gcloud builds submit --tag gcr.io/${GOOGLE_PROJECT_ID}/test .

コミット、プッシュをして動作させます。
circleciコマンドが入っている場合、下記のように validate を掛けておくと構文エラーをへらすことができます。

$ circleci config validate && git add .circleci/config.yml &&  git commit -m 'Add CircleCI config' && git push origin HEAD

CircleCIでのビルドを確認します。

image.png

問題がなければ正しくビルドされ、GCRにイメージが作成されているはずです。

費用など

GCRでは Cloud Storage としてイメージが保管されるため、月々の費用がかかります。
2020年7月現在、概算で下記の通りです。

Standard のバケット料金は、1 GB あたり月額約 $0.026 です。
https://cloud.google.com/container-registry/pricing?hl=ja

巨大なイメージを管理する場合には注意が必要です。

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

Ubuntu 16.04へのIcinga2監視ツールのインストールと設定

Ubuntu 16.04にIcinga2監視ツールをインストールして設定する方法を探り、またAlibaba CloudDockerをインストールして、いくつかの重要なDockについて学んでいきます。

本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。

序章

Icinga 2 はフリーでオープンソースの強力なネットワークリソース監視ソフトウェアアプリケーションで、ネットワークからのリソースの可用性をチェックし、停止をユーザーに通知し、レポート用のパフォーマンスデータを生成します。Icinga 2を使用して、ネットワークサービス(SMTP、POP3、HTTP、NNTP、ping)、ホストリソース(CPU負荷、ディスク使用量)、ネットワークコンポーネント(スイッチ、ルーター、温度・湿度センサー)を監視することができます。これはNagiosシステム監視アプリケーションに非常に似ています。Icinga 2をNagiosプラグインと簡単に統合することができます。Icinga 2には、複数の場所にまたがる大規模で複雑な環境を監視するための、美しくユーザーフレンドリーなウェブインターフェースが付属しています。

Icinga 2には様々な機能が搭載されていますが、以下にその一部をご紹介します。

  • GraphiteとInfluxDBをネイティブにサポートしています。
  • 問題が発生した場合、電子メールやテキストメッセージで通知を送信します。
  • カスタマイズ可能なプラグインにより、独自のサービスチェックを簡単に開発することができます。
  • ホストとサービスの状態、ネットワークマップ、レポート、ログなどを可視化するためのIcinga Classic UIとIcinga Webインターフェイスを提供します。
  • パフォーマンスグラフ化のためのPNP4Nagios、NagiosGrapher、InGraphなどの追加アドオンをサポートします。

このチュートリアルでは、Ubuntu 16.04サーバにIcinga 2とIcinga web 2をインストールして設定する方法を学びます。また、リモートホストサービスを監視するためにicinga2を設定する方法も学びます。

前提条件

  • Alibaba Cloud Instance for Icinga ServerとUbuntu 16.04がインストールされています。
  • Alibaba Cloud Instance for Icinga Client with Ubuntu 16.04がインストールされています。
  • 静的IPアドレス192.168.0.103がIcinga Server Instanceに設定されています。
  • 静的IPアドレス192.168.0.104がIcingaクライアントインスタンスに設定されています。
  • ドメイン名に適切なDNSレコードが設定されています。
  • SSHサービス経由でルートアカウントにアクセスできます。

はじめに

始める前に、以下のコマンドでシステムリポジトリとソフトウェアパッケージを最新バージョンに更新してください。

apt-get update -y
apt-get upgrade -y

次に、システムのホスト名を設定する必要があります。これは以下のコマンドで行うことができます。

hostnamectl set-hostname icingaserver

次に、以下のコマンドでシステムのホスト名を確認します。

hostnamectl

次に、サーバーインスタンスを再起動して、以下のコマンドですべてのアップデートを適用します。

reboot

必要なパッケージのインストール

Icinga 2はウェブサーバー上で動作するので、Apacheサーバー、MariaDB、PHP言語、必要なPHPモジュールをシステムにインストールする必要があります。以下のコマンドを実行するだけで、すべてのパッケージをインストールすることができます。

apt-get install apache2 libapache2-mod-php7.0 mariadb-server mariadb-client php7.0 php7.0-xml php7.0-pgsql php7.0-opcache php7.0-xml php7.0-ldap php7.0-cli php7.0-gd php7.0-intl php7.0-readline php7.0-mbstring php7.0-json php7.0-curl php7.0-mysql -y

必要なパッケージがすべてインストールされたら、以下のコマンドを使ってApacheとMariaDBサービスを起動し、起動時に起動できるようにします。

systemctl start apache2
systemctl enable apache2
systemctl start mysql
systemctl enable mysql

次に、以下のコマンドを使用して、Apache rewrite モジュールを有効にして、HTTP 接続を HTTPS にリダイレクトします。

a2enmod rewrite

次に、システムの地理的な位置と一致するタイムゾーンを設定する必要があります。これはphp.iniファイルを編集することによって行うことができます。

nano /etc/php/7.0/apache2/php.ini

次の行を変更します。

date.timezone = Asia/Kolkata

保存して終了したらファイルを閉じ、Apache サービスを再起動して変更を適用します。

systemctl restart apache2

Icinga2とIcinga Web 2のインストール

デフォルトでは、Ubuntu 16.04のデフォルトリポジトリでは、最新版のIcingaは利用できません。そのため、Icinga用のソフトウェアリポジトリを追加する必要があります。

まず、以下のコマンドでIcingaのパッケージ署名キーをダウンロードして追加します。

curl -sSL https://packages.icinga.com/icinga.key | sudo apt-key add -

次に、APT設定ファイルにIcingaリポジトリを追加します。

nano /etc/apt/sources.list.d/icinga.list

ファイルの最後に以下の行を追加します。

deb https://packages.icinga.com/ubuntu icinga-xenial main

保存してファイルを閉じ、以下のコマンドでリポジトリを更新します。

apt-get update -y

リポジトリが更新されたら、以下のコマンドでIcinga2とIcinga web 2をインストールします。

apt-get install icinga2 icingaweb2 icinga2-ido-mysql -y

インストール中に、アプリケーションを設定するための一連の質問を受けます。以下に示すように、それぞれの質問に答えてください。

Enable Icinga 2's ido-mysql feature? YES
Configure database for icinga2-ido-mysql with dbconfig-common? NO

次に、Icinga 2のido-mysqlとコマンド機能を有効にする必要があります。これは以下のコマンドを使って行うことができます。

icinga2 feature enable ido-mysql
icinga2 feature enable command

最後に、以下のコマンドでIcinga2サービスを再起動し、起動時に起動できるようにします。

systemctl restart icinga2
systemctl enable icinga2

データベースの設定

開始前に、MariaDB データベースのセキュリティを確保する必要があります。これは、mysql_secure_installationスクリプトを実行することで行うことができます。

mysql_secure_installation

このスクリプトは、以下のようにMySQLのルートパスワードの変更、匿名ユーザーの削除、リモートルートログインの無効化、テストデータベースの削除を行います。

Change the root password? [Y/n] n
Remove anonymous users? [Y/n] y
Disallow root login remotely? [Y/n] y
Remove test database and access to it? [Y/n] y
Reload privilege tables now? [Y/n] y

MariaDBのセキュリティが確保されたら、MariaDBシェルにログインし、以下のコマンドでIcinga2 IDO用の強力なパスワードを持つデータベース、データベースユーザーを作成します。

mysql -u root -p

MariaDB [(none)]> CREATE DATABASE icinga2;
MariaDB [(none)]> GRANT ALL PRIVILEGES on icinga2.* to 'icinga2'@'localhost' identified by 'strongpassword';
MariaDB [(none)]> FLUSH PRIVILEGES;
MariaDB [(none)]> exit;

次に、データベース、Icinga web 2用の強力なパスワードを持つデータベースユーザーを作成する必要があります。 これは、以下のコマンドを使用して行うことができます。

MariaDB [(none)]> CREATE DATABASE icingaweb2db;
MariaDB [(none)]> GRANT ALL PRIVILEGES on icingaweb2db.* to 'icingaweb2'@'localhost' identified by 'strongpassword';
MariaDB [(none)]> FLUSH PRIVILEGES;
MariaDB [(none)]> exit;

次に、Icinga2 IDOスキーマをIcinga2データベースにインポートする必要があります。これは以下のコマンドを使用して行うことができます。

mysql -u root icinga2 -p < /usr/share/icinga2-ido-mysql/schema/mysql.sql

次に、Icinga2 MySQL IDO設定ファイルを編集して、データベースの資格情報を手動で更新する必要があります。これは、/etc/icinga2/features-enabled/ido-mysql.confファイルを編集することで行うことができます。

nano /etc/icinga2/features-enabled/ido-mysql.conf

以下のようにファイルを変更します。

user = "icinga2",
password = "strongpassword",
host = "localhost",
database = "icinga2"

ファイルを保存して閉じ、変更を適用するためにIcinga2サービスを再起動します。

systemctl restart icinga2

ファイアウォールを介してIcinga2を許可する

デフォルトでは、新しくインストールされたUbuntu 16.04サーバインスタンスでは、UFWファイアウォールは無効になっています。UFWファイアウォールを有効にするには、以下のコマンドを使用します。

ufw enable 

次に、以下のコマンドでApacheのポート80、443、5665を許可します。

ufw allow 80
ufw allow 443
ufw allow 5665
ufw reload

Webインタフェースを使ってIcinga2を設定する

Icinga Web 2は、インフラストラクチャの問題を監視したり、ホストやサービスの健全性を確認したりするために使用できるIcinga 2のWebインターフェースです。

Icinga Web 2 インターフェイスにアクセスする前に、ウェブセットアップツールの使用を許可するセットアップトークンを作成する必要があります。これは以下のコマンドで作成できます。

icingacli setup token create

以下のような出力が表示されるはずです。

The newly generated setup token is: 4630c2921fca4da8

上記のトークンをコピーし、ウェブブラウザを開いてURL http://your-domain.com/icingaweb2 または http://your-server-ip/icingaweb2 を入力すると、以下のようなIcinga web 2のセットアップウィザードにリダイレクトされます。

image.png

さて、先ほどコピーしたトークンをSetup Tokenフィールドに貼り付け、Nextボタンをクリックして処理を開始します。

image.png

ここでは、有効にしたいモジュールを選択する必要があります。DocとMonitoringモジュールを有効にして、次へボタンをクリックすると、次のようなページが表示されるはずです。

image.png

ここで、Icinga2はあなたのシステム要件をチェックします。必要なPHPモジュールがすべてインストールされていることを確認し、「次へ」ボタンをクリックすると、次のようなページが表示されます。

image.png

ここでは、Icinga webにアクセスするための認証メカニズムを選択する必要があります。 Authentication Type = Databaseを選択し、Nextボタンをクリックすると、以下のようなページが表示されるはずです。

image.png

ここでは、Icinga web 2のデータベース認証情報を入力して、データベース名、ユーザー名、パスワードを入力し、次へボタンをクリックすると、次のページが表示されます。

image.png

次に、データベース認証の名前を定義して「次へ」ボタンをクリックすると、以下のようなページが表示されるはずです。

image.png

ここで、管理者アカウントのクレデンシャルを入力して、Icinga2のWebインターフェースにログインし、「次へ」ボタンをクリックすると、次のようなページが表示されます。

image.png

ここで、Icinga2のアプリケーションとログ情報を提供し、次へボタンをクリックすると、次のページが表示されるはずです。

image.png

さて、すべての設定を確認して「次へ」ボタンをクリックすると、次のようなページが表示されるはずです。

image.png

ここで、[次へ]ボタンをクリックして設定処理を開始します。

image.png

ここでは、Icinga web 2 Backendの名前とBackendの種類を入力し、Nextボタンをクリックすると、次のようなページが表示されるはずです。

image.png

ここで、Icinga2 IDOデータベースの認証情報を入力し、「次へ」ボタンをクリックすると、次のようなページが表示されます。

image.png

[次へ]ボタンをクリックして、セットアッププロセスを続行します。次のようなページが表示されるはずです。

image.png

ここでは、Icinga2が提供するデフォルト値のままで、次へボタンをクリックすると、以下のようなページが表示されるはずです。

image.png

ここで、これまでに行ったすべての設定を確認し、「完了」ボタンをクリックしてインストールを完了させます。インストールが正常に設定されると、以下のページが表示されるはずです。

image.png

ここで、「Login to icinga web 2」ボタンをクリックすると、以下のようなページが表示されるはずです。

image.png

ここで、以前に作成した管理者アカウントの認証情報を入力し、ログインボタンをクリックすると、以下のようなIcinga web 2のダッシュボードが表示されます。

image.png

リモートホストの監視のためにIcinga2マスターノードを設定する

これでIcinga web 2の設定が完了したので、Icinga2サーバーノードを設定して監視用のマスターにしましょう。これは以下のコマンドを実行することで行うことができます。

icinga2 node wizard

セットアップの過程で、いくつかの質問がありますので、以下に示すようにすべての質問に答えてください。

Welcome to the Icinga 2 Setup Wizard!

We'll guide you through all required configuration details.

Please specify if this is a satellite setup ('n' installs a master setup) [Y/n]: n
Starting the Master setup routine...
Please specify the common name (CN) [icingaserver]: 
Checking for existing certificates for common name 'icingaserver'...
Certificates not yet generated. Running 'api setup' now.
information/cli: Generating new CA.
information/base: Writing private key to '/var/lib/icinga2/ca/ca.key'.
information/base: Writing X509 certificate to '/var/lib/icinga2/ca/ca.crt'.
information/cli: Generating new CSR in '/etc/icinga2/pki/icingaserver.csr'.
information/base: Writing private key to '/etc/icinga2/pki/icingaserver.key'.
information/base: Writing certificate signing request to '/etc/icinga2/pki/icingaserver.csr'.
information/cli: Signing CSR with CA and writing certificate to '/etc/icinga2/pki/icingaserver.crt'.
information/pki: Writing certificate to file '/etc/icinga2/pki/icingaserver.crt'.
information/cli: Copying CA certificate to '/etc/icinga2/pki/ca.crt'.
Generating master configuration for Icinga 2.
information/cli: Adding new ApiUser 'root' in '/etc/icinga2/conf.d/api-users.conf'.
information/cli: Enabling the 'api' feature.
Enabling feature api. Make sure to restart Icinga 2 for these changes to take effect.
information/cli: Dumping config items to file '/etc/icinga2/zones.conf'.
information/cli: Created backup file '/etc/icinga2/zones.conf.orig'.
Please specify the API bind host/port (optional):
Bind Host []: 
Bind Port []: 
information/cli: Created backup file '/etc/icinga2/features-available/api.conf.orig'.
information/cli: Updating constants.conf.
information/cli: Created backup file '/etc/icinga2/constants.conf.orig'.
information/cli: Updating constants file '/etc/icinga2/constants.conf'.
information/cli: Updating constants file '/etc/icinga2/constants.conf'.
information/cli: Updating constants file '/etc/icinga2/constants.conf'.
Done.

Now restart your Icinga 2 daemon to finish the installation!

次に、Icinga2サービスを再起動し、マスターノードの設定を適用します。

systemctl icinga2 restart

次に、Icinga 2マスターノードもクライアントから有効なチケットが必要なので、Icinga 2クライアントノード用のチケットを生成する必要があります。

以下のコマンドを使って同じものを生成します。

icinga2 pki ticket --cn 'icingaclient'

以下のような出力が表示されるはずです。

582f9fda5c5823440e63ea0f083d105b81237b37

監視用のリモートクライアントノードを設定する

始める前に、クライアントノードにIcinga 2とNagiosプラグインをインストールする必要があります。まず、以下のコマンドを使ってIcingaパッケージ署名キーをダウンロードして追加します。

curl -sSL https://packages.icinga.com/icinga.key | sudo apt-key add -

次に、APT設定ファイルにIcingaリポジトリを追加します。

nano /etc/apt/sources.list

ファイルの最後に以下の行を追加します。

deb https://packages.icinga.com/ubuntu icinga-xenial main

保存してファイルを閉じ、以下のコマンドでリポジトリを更新します。

apt-get update -y

リポジトリが更新されたら、以下のコマンドでIcinga2とNagiosプラグインをインストールします。

apt-get install icinga2 nagios-plugins -y

次に、以下のコマンドでIcinga 2サービスを起動し、起動時に起動できるようにします。

systemctl start icinga2
systemctl enable icinga2

次に、以下のようにクライアントノード上でIcinga 2ノードウィザードを実行します。

icinga2 node wizard

以下のように、すべての質問に答えてください。

Welcome to the Icinga 2 Setup Wizard!

We will guide you through all required configuration details.

Please specify if this is a satellite/client setup ('n' installs a master setup) [Y/n]: Y

Starting the Client/Satellite setup routine...

Please specify the common name (CN) [icingaclient]: 

Please specify the parent endpoint(s) (master or satellite) where this node should connect to:
Master/Satellite Common Name (CN from your master/satellite node): icingaserver

Do you want to establish a connection to the parent node from this node? [Y/n]: Y
Please specify the master/satellite connection information:
Master/Satellite endpoint host (IP address or FQDN): 192.168.0.103
Master/Satellite endpoint port [5665]: 5665

Add more master/satellite endpoints? [y/N]: N
Parent certificate information:

 Subject:     CN = icingaserver
 Issuer:      CN = Icinga CA
 Valid From:  Dec 29 15:13:35 2017 GMT
 Valid Until: Dec 25 15:13:35 2032 GMT
 Fingerprint: 53 5A BC BE 57 D3 1B F7 D0 A4 D7 F2 F4 2A 44 2F 64 53 D7 A0 

Is this information correct? [y/N]: y

Please specify the request ticket generated on your Icinga 2 master (optional).
 (Hint: # icinga2 pki ticket --cn 'icingaclient'): 582f9fda5c5823440e63ea0f083d105b81237b37

Please specify the API bind host/port (optional):
Bind Host []: 
Bind Port []: 

Accept config from parent node? [y/N]: y
Accept commands from parent node? [y/N]: y

Reconfiguring Icinga...
Disabling feature notification. Make sure to restart Icinga 2 for these changes to take effect.
Enabling feature api. Make sure to restart Icinga 2 for these changes to take effect.

Done.

Now restart your Icinga 2 daemon to finish the installation!

ここで、すべての設定を適用するために、Icinga2サーバーを再起動します。

systemctl restart icinga2

これで、Icinga 2のマスターノードとクライアントノードが接続されました。また、監視したいクライアントを定義するために、Icinga 2のマスターノードにゾーンファイルを設定する必要があります。

マスターノードに戻り、ゾーンディレクトリを作成します。

nano mkdir /etc/icinga2/zones.d/icingaclient

次に、以下のコマンドでサービスファイルとホストファイルを作成します。

nano /etc/icinga2/zones.d/icingaclient/service.conf

以下の行を追加します。

apply Service "load" {
  import "generic-service"
  check_command = "load"
  command_endpoint = host.vars.client_endpoint
  assign where host.vars.client_endpoint
}

apply Service "procs" {
  import "generic-service"
  check_command = "procs"
  command_endpoint = host.vars.client_endpoint
  assign where host.vars.client_endpoint
}

保存してからホストファイルを作成します。

nano /etc/icinga2/zones.d/icingaclient/icingaclient.conf

以下の行を追加します。

object Zone "icingaclient" {
  endpoints = [ "icingaclient" ]
  parent = "icingaserver"
}

object Endpoint "icingaclient" {
  host = "192.168.0.104"
}

object Host "icingaclient" {
  import "generic-host"
  address = "192.168.0.104"
  vars.os = "Linux"
  vars.notification["mail"] = {
    groups = [ "icingaadmins" ]
  }
  vars.client_endpoint = name
}

ホスト名とIPアドレスがクライアントノードと一致していることを確認してください。ファイルを保存し、以下のコマンドでIcinga 2サービスを再起動します。

systemctl restart icinga2

ここで、Icinga web 2のインターフェイスを開き、Overview > Hostsタブをクリックすると、新しく追加されたクライアントノードが表示されるはずです。

結論

おめでとうございます!これで、Ubuntu 16.04サーバーにIcinga2サーバーとIcinga web 2をインストールして設定することができました。これで、IcingaのWebインターフェースを使って、中央の場所から簡単にインフラ全体を監視することができます。詳細については、https://www.icinga.com/docs/ の Icinga ドキュメントページを参照してください。

アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ

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

DockerでDjangoアプリケーションをデプロイする

Dockerは、コンテナを利用してアプリケーションの作成、デプロイ、実行を容易にする技術です。

本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。

Dockerとは?

Dockerは、コンテナを利用してアプリケーションの作成、デプロイ、実行を容易にする技術です。コンテナを使うことで、開発者はアプリケーションに必要なすべてのコンポーネントをパッケージ化し、後からパッケージとして出荷することができます。また、同じサーバー上でより多くのアプリケーションを稼働させることも可能になります。

Dockerを使えば、コンテナ上で動作しているアプリケーションは互いに隔離されているため、より高いレベルのセキュリティを確保することができます。さらに、Dockerは各コンテナが独自のリソースを持っていることを保証するので、アプリケーションは割り当てられたリソースのみを使用することになります。

前提条件

このガイドを開始する前に、以下のものが必要です。

  • Alibaba Cloud ECS Linuxインスタンス。まだLinuxインスタンスをセットアップしていない場合は、この記事で様々なセットアップ方法を紹介します。
  • Docker
  • Python 2.7

Dockerのインストール

ssh コマンドを使ってサーバにログインします。

$ ssh root@47.88.220.88

Ubuntuのパッケージを更新します。

$ sudo apt-get update

以下のコマンドで最新版のDockerをインストールします。

$ sudo apt-get install docker

Dockerが正しくインストールされていることを確認するには、以下のコマンドを実行します。

$ sudo docker run hello-world

正しく実行すれば、上記のコマンドでインスタンスがテストイメージをダウンロードしてコンテナ内で実行できるようになるはずです。

Dockerでのコンテナとイメージ

Alibaba Cloud ECSインスタンスでは、イメージを使用して同じ構成のECSクラスタを作成することができます。同様に、Dockerコンテナにもイメージがあります。概念的には、両者は非常に似ています。Dockerの公式ドキュメントに基づいています。

コンテナイメージは、軽量でスタンドアロンの実行可能なソフトウェアのパッケージであり、それを実行するために必要なすべてのものが含まれています: コード、ランタイム、システムツール、システムライブラリ、設定。

実行中のコンテナは、$ sudo docker psを実行することで見ることができます。

一方、イメージとは、コンテナのスナップショットのような不活性で不変なファイルのことです。イメージは build コマンドで作成され、run コマンドで起動するとコンテナを生成します。

イメージは $ sudo docker images を実行することで見ることができます。

Djangoアプリケーションを構築する

まずはDjangoをインストールしてDjangoアプリケーションを作成してみましょう。

$ sudo pip install django==1.9
$ django-admin startproject djangoapp

要件ファイル

djangoapp ディレクトリ内に要件ファイルを作成し、アプリケーションが必要とする依存関係を定義します。

$ cd djangoapp
$ nano requirements.txt

以下の依存関係を追加します。

#requirements.txt

Django==1.9
gunicorn==19.6.0

Dockerファイルの作成

Dockerには、Dockerファイルから命令を読み込んで自動的にイメージを構築する機能があります。Dockerファイルには、Dockerがイメージを構築するために使用するすべてのコマンドと命令が含まれています。

Dockerfileで使用される基本的なコマンドをいくつか定義してみましょう。

  • FROM - 新しいビルドステージを初期化し、その後の命令のためのベースイメージを設定します。そのため、有効なDockerfileはFROM命令で始まらなければなりません。
  • RUN - 指定されたコマンドを実行します。
  • ADD - コンテナにファイルをコピーします。
  • EXPOSE - 実行時にコンテナが指定されたネットワークポートをリッスンしていることをDockerに通知します。
  • CMD - 実行中のコンテナにデフォルトを提供します。 では、Dockerfileというファイルを作成してみましょう。

$ nano Dockerfile

まずはDockerfileに必要なプロパティをすべて定義してみましょう。ベースイメージとメンテナ名を定義します。

# base image 
FROM python:2.7

# File Author / Maintainer
MAINTAINER Esther

次に、コンテナ内のアプリケーションフォルダをコピーし、CMDが実行されるディレクトリを定義します。

# Copy the application folder inside the container
ADD . /usr/src/app

# set the default directory where CMD will execute
WORKDIR /usr/src/app

最後にデフォルトのコマンドを設定して実行します。

CMD exec gunicorn djangoapp.wsgi:application --bind 0.0.0.0:8000 --workers 3

最終的なDockerfileは以下のようになるはずです。

# set the base image 
FROM python:2.7

# File Author / Maintainer
MAINTAINER Esther

#add project files to the usr/src/app folder
ADD . /usr/src/app

#set directoty where CMD will execute 
WORKDIR /usr/src/app

COPY requirements.txt ./

# Get pip to download and install requirements:
RUN pip install --no-cache-dir -r requirements.txt

# Expose ports
EXPOSE 8000

# default command to execute    
CMD exec gunicorn djangoapp.wsgi:application --bind 0.0.0.0:8000 --workers 3 

Dockerイメージの構築

以下のコマンドを実行して、dockerイメージを構築します。

$ sudo docker build -t django_application_image .

Sending build context to Docker daemon   12.8kB
Step 1/7 : FROM python:2.7
 ---> 2863c80c418c
Step 2/7 : ADD . /usr/src/app
 ---> 09b03ff8466e
Step 3/7 : WORKDIR /usr/src/app
Removing intermediate container a71a3bf6af90
 ---> 3186c92adc85
Step 4/7 : COPY requirements.txt ./
 ---> 701c0be5e039
Step 5/7 : RUN pip install --no-cache-dir -r requirements.txt
 ---> Running in ed034f98db74
Collecting Django==1.9 (from -r requirements.txt (line 1))
  Downloading Django-1.9-py2.py3-none-any.whl (6.6MB)
Collecting gunicorn==19.6.0 (from -r requirements.txt (line 2))
  Downloading gunicorn-19.6.0-py2.py3-none-any.whl (114kB)
Installing collected packages: Django, gunicorn
Successfully installed Django-1.9 gunicorn-19.6.0
Removing intermediate container ed034f98db74
 ---> 1ffd08204a07
Step 6/7 : EXPOSE 8000
 ---> Running in 987b48e1a4ef
Removing intermediate container 987b48e1a4ef
 ---> ef889d6e8fcb
Step 7/7 : CMD exec gunicorn djangoapp.wsgi:application --bind 0.0.0.0:8000 --workers 3
 ---> Running in 4d929e361d0f
Removing intermediate container 4d929e361d0f
 ---> c6baca437c64
Successfully built c6baca437c64
Successfully tagged django_application_image:latest

構築されたイメージは、マシンのローカルのDockerイメージレジストリにあります。イメージを確認するには、$ sudo docker images を実行します。

REPOSITORY                 TAG                 IMAGE ID            CREATED             SIZE
django_application_image   latest              c6baca437c64        34 minutes ago      702MB

アプリを実行する

$ sudo docker run -p 8000:8000 -i -t django_application_image

[2018-03-25 12:29:08 +0000] [1] [INFO] Starting gunicorn 19.6.0
[2018-03-25 12:29:08 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000
[2018-03-25 12:29:08 +0000] [1] [INFO] Using worker: sync
[2018-03-25 12:29:08 +0000] [8] [INFO] Booting worker with pid: 8
[2018-03-25 12:29:08 +0000] [9] [INFO] Booting worker with pid: 9
[2018-03-25 12:29:08 +0000] [10] [INFO] Booting worker with pid: 10

gunicorn がアプリにサービスを提供しているというメッセージがhttp://0.0.0.0:8000に表示されます。 サーバーの IP (ip_address:8000) に移動し、Django のウェルカムページが表示されるはずです。

実行中のコンテナを見るには

$ sudo docker ps -a
CONTAINER ID        IMAGE                      COMMAND                  CREATED             STATUS                           PORTS                            NAMES
100695b41a0a        django_application_image   "/bin/sh -c 'exec gu…"   13 seconds ago      Exited (0) 4 seconds ago                                          hopeful_easley

結論

Dockerを使っていると、時としていくつかの問題に直面することがあります。エラーが発生したときに最初にすべきことは、Dockerのログファイルをチェックすることです。

Dockerやその他のコンテナは、アプリケーション開発のための従来の仮想マシンの強力な代替手段です。Alibaba Cloud上でコンテナを実行する方法の詳細については、コンテナサービスのページをご覧ください。

アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ

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

【Rails6】hamlを導入したらmissing a templateエラーが発生したときの対処法【超簡単】

hamlのメリット

  • 閉じタグや<% end %>が必要なくなり、簡潔にかける。
  • インデントがきちっとしていないとエラーになるので嫌でも綺麗にかける。

上記のメリットに加えて、現場でも使われる機会が多いので、勉強がてらRailsにhamlを導入してみました。
そのときmissing a templateというエラーが発生し少し困ったのでここへメモとして残しておきます。
このページを見ているということは既にhamlを導入済身の方が多いと思うので一番下の解決方法へ飛んでください。
そうでない方のためにも、hamlの導入方法についても解説します。

(環境)

  • windows10 Pro
  • Rails: 6.0.3.2
  • ruby: 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]
  • Docker for windows
  • MySQL 5.6
  • nginx:1.15.8

hamlの導入方法

1.Gemを追記

Gemfile
gem 'haml-rails'

2.いつものやつ

$ docker-compose exec サービス名 bundle

開発環境にDockerを使っているのでdocker-compose exec サービス名 を付けてます。
これでhamlの導入は完了です。

erbファイルをhamlに変換

$ docker-compose exec サービス名 rails haml:erb2haml

たったこれだけでerbファイルをhamlへ変換してくれます。

missing a templateエラーが発生

ActionController::UnknownFormat (PostsController#index is missing a template
 for this request format and variant.

request.formats: ["text/html"]
request.variant: []

NOTE! For XHR/Ajax or API requests, this action would normally respond with
204 No Content: an empty white screen. Since you're loading it in a web
browser, we assume that you expected to actually render a template, not
nothing, so we're showing an error to be extra-clear. If you expect 204 No
Content, carry on. That's what you'll get from an XHR or API request. Give
it a shot.)

localhostにアクセスしたら上記のようなエラーが出てviewが表示されなくなりました。

解決方法

解決方法はサーバーを再起動するだけ。(rails s)
僕の場合は開発環境にdockerを使っていたのでコンテナを再起動しました。

$ docker-compose restart

これで解決すると思います。
視野が狭くなると再起動するという発想すらでなくなり迷宮入りしかけました。
エラーが起きた時は視野を広く持てるように気を付けたいです。

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

dockerで共有ボリュームを試してみる

複数のコンテナ間でストレージを共有したい、ということで
こちらのサイトを参考に試してみる。

やること

share、mainという2つのコンテナを作成。
 コンテナ起動時にそれぞれ以下のようにボリュームオプションを指定
 share: -v /data/vol0001 ※共有ディレクトリ作成
 main : --volumes-from share ※shareのボリュームオプションを引き継ぐ

起動したら共有ボリュームにファイルを作成し
それぞれのコンテナからきちんと見えることを確認する。

shareコンテナ起動

shareコンテナ起動
$ docker container run -it -d -v /data/vol0001 --name share registry.access.redhat.com/ubi7/ubi:latest /bin/bash
c72dff13bff397a38c70d3b45ba022ffb3f808b9124296971568396e8ec4d1e6
$
$ docker container ls -a
CONTAINER ID        IMAGE                                        COMMAND             CREATED             STATUS              PORTS               NAMES
c72dff13bff3        registry.access.redhat.com/ubi7/ubi:latest   "/bin/bash"         10 seconds ago      Up 9 seconds                            share
$

mainコンテナ起動

mainコンテナ起動
$ docker container run -it -d --volumes-from share --name main registry.access.redhat.com/ubi7/ubi:latest /bin/bash
e942908dca92c1a2f76d78bb256d4403442b5e89cd86e45a1feb7dcb957bafa6
$
$ docker container ls -a
CONTAINER ID        IMAGE                                        COMMAND             CREATED             STATUS              PORTS               NAMES
e942908dca92        registry.access.redhat.com/ubi7/ubi:latest   "/bin/bash"         3 seconds ago       Up 2 seconds                            main
c72dff13bff3        registry.access.redhat.com/ubi7/ubi:latest   "/bin/bash"         2 minutes ago       Up 2 minutes                            share
$

shareコンテナに入り、共有ボリュームにファイルを作成

shareコンテナ側からファイル作成
$ docker container exec -it share /bin/bash
#
# cd /data/vol0001
# echo "this is share" > test.txt
# cat test.txt
this is share
# exit
exit
$

mainコンテナに入り、共有ボリュームを確認し追記

mainコンテナ側から追記
$ docker container exec -it main /bin/bash
# cd /data/vol0001
# ls -l
total 4
-rw-r--r-- 1 root root 14 Jun 28 12:44 test.txt
#
# cat test.txt
this is share
#
# echo "this is main" >> test.txt
#
# cat test.txt
this is share
this is main
#
# exit
exit
$

shareコンテナで追記内容を確認

shareコンテナ側で確認
$ docker container exec share cat /data/vol0001/test.txt
this is share
this is main
$

shareコンテナを停止してもmainから共有ボリュームが見れるか

shareコンテナ停止
$ docker container stop share
share
$

$ docker container ls -a
CONTAINER ID        IMAGE                                        COMMAND             CREATED             STATUS                        PORTS               NAMES
e942908dca92        registry.access.redhat.com/ubi7/ubi:latest   "/bin/bash"         13 minutes ago      Up 8 minutes                                      main
c72dff13bff3        registry.access.redhat.com/ubi7/ubi:latest   "/bin/bash"         15 minutes ago      Exited (137) 13 seconds ago                       share
$

$ docker container exec main cat /data/vol0001/test.txt
this is share
this is main
$

問題なく見える

shareコンテナを削除してもmainから共有ボリュームが見れるか

shareコンテナ削除
$ docker container rm share
share
$

$ docker container ls -a
CONTAINER ID        IMAGE                                        COMMAND             CREATED             STATUS              PORTS               NAMES
e942908dca92        registry.access.redhat.com/ubi7/ubi:latest   "/bin/bash"         14 minutes ago      Up 9 minutes                            main
$

$ docker container exec main cat /data/vol0001/test.txt
this is share
this is main
$

問題なく見える

後片付け

後片付け
$ docker container rm -f main
main
$

$ docker container ls -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
$

気になったことを調べてみる

run時に -v /data/vol0001 でdockerボリュームを作成したが
このボリュームはどこに存在するのか。

下記サイトのおかげで疑問は解消。
https://karuta-kayituka.hatenablog.com/entry/2019/05/04/114056

ファイル内のVOLUMEが指すものは、どこに存在するものなのか?(ホストのどこか?)
⇒ホストに存在するが特定のディレクトリと共有してるわけではなく、
 docker volumeとして作成された新たなボリュームを指している

docker runのvオプションとはVOLUMEは別物なのか?
⇒同じである。 名前付きかどうかという違いがあるぐらいだ

また、共有ボリュームは docker volume ls で確認できるが
名前がハッシュ値になっているためどれがどれだか分からなかった。
これはdocker volume createで事前にボリュームを作成せず
docker run -vで自動で新規作成してしまったため(自動作成だと名前がハッシュになる)。

docker volume create v1
のように明示的に名前を指定してボリュームを作成し
docker container run -v v1:/data/vol0001 …
のようにコンテナ起動するべきだった。

ということで、きちんと後片付けしたつもりだったが
共有ボリュームが残っていることが分かったので docker volume で削除。

共有ボリューム削除
$ docker volume rm 5e123abdf19ececb4e3791aeedafc2d7bc8c50bfaeccbdf8f4c1df7b99d4a019
5e123abdf19ececb4e3791aeedafc2d7bc8c50bfaeccbdf8f4c1df7b99d4a019
$
$ docker volume ls
DRIVER              VOLUME NAME
$

個人メモ
 dockerボリュームはホスト上に存在するので
 fargateだと同じことはできなそう。そのためのEFSのはず。

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

USBカメラをDockerから使いたい

概要

UVC対応のUSBカメラ(BUFFALO BSW200MBK)をDockerから使おうとしてつまずいたので、試したことをまとめます。
本記事ではROSを利用していますが、ROS側の問題では無いはずです。

ホスト

  • HP Spectre x360 2019年モデル
    • intel i7-1065G7
    • intel CPU内蔵グラフィック
  • Ubuntu 18.04
  • Docker version 19.03.12, build 48a66213fe
  • 一般ユーザーはsudo gpasswd -a $USER dockerとして、sudoなしで起動できるように設定済み

試したこと

次のようなDockerfileを作成して、

FROM ubuntu:16.04

# 中略 ROS kinetic のインストール

RUN apt-get update && apt-get install -y \
  ros-kinetic-uvc-camera

RUN useradd -m -d /home/myubuntu16 myubuntu16 -p $(perl -e 'print crypt("myubuntu16", "salt"),"\n"') && \
    echo "myubuntu16 ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

RUN \
  apt-get update && \
  apt-get -y install libgl1-mesa-glx libgl1-mesa-dri && \
  rm -rf /var/lib/apt/lists/*

ENV QT_X11_NO_MITSHM 1

ENV USER myubuntu16
USER myubuntu16

CMD ["bash"]

次のコマンドでコンテナを起動しました。

docker build -t myubuntu:16 .

docker run  -it \
    --name myubuntu_test \
    --volume=/tmp/.X11-unix:/tmp/.X11-unix \
    --volume=$(pwd)/myubuntu16:/home/myubuntu16  \
    --device=/dev/dri:/dev/dri \
    --device=/dev/video0:/dev/video0 \
    --env="DISPLAY=$DISPLAY"   \
    myubuntu:16

立ち上がったコンテナでroscoreを起動して、別のターミナルから同じコンテナに入って、カメラを起動するノードを立ち上げたところでエラーが発生。

# ターミナル2
$ docker exec -it myubuntu_test bash
$ rosrun uvc_camera uvc_camera_node 
[ INFO] [1594303093.006722031]: using default calibration URL
[ INFO] [1594303093.006790555]: camera calibration URL: file:///home/myubuntu16/.ros/camera_info/camera.yaml
[ INFO] [1594303093.006832237]: Unable to open camera calibration file [/home/myubuntu16/.ros/camera_info/camera.yaml]
[ WARN] [1594303093.006850909]: Camera calibration file /home/myubuntu16/.ros/camera_info/camera.yaml not found.
opening /dev/video0
terminate called after throwing an instance of 'std::runtime_error'
  what():  couldn't open /dev/video0
Aborted

couldn't open /dev/video0と出たので、カメラの状態を取得するツール(?)を実行

$ sudo apt install v4l-utils
$ v4l2-ctl --list-device
Failed to open /dev/video0: Permission denied

権限を確認して、変更してみるとPermission deniedは解消された。

$ ls -la /dev/video*
crw-rw---- 1 root video 81, 0 Jul  9 13:48 /dev/video0

$ sudo chmod 777 /dev/video0
$ v4l2-ctl --list-device
USB_Camera: USB_Camera (usb-0000:00:14.0-1):
    /dev/video0

ふたたび、同じコンテナ内の3個のターミナルで以下をそれぞれ実行

$ roscore
$ rosrun uvc_camera uvc_camera_node
$ rosrun image_view image_view image:=/image_raw

動いた

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

プログラムの怖いところ ライブラリのバージョンアップ

はじめに

本記事はライブラリのバージョンアップが原因でプログラムが動かなくなり、どの様に原因を調査して解決まで行き着いたかについて、システム開発の一助となるストーリーをご紹介します。

概要

とあるtoCのシステムにおけるバックエンドのプログラム(API)で軽微な修正を行い、デプロイしたときの話になります。

本番環境と開発環境が存在し、開発環境でテストした上で本番環境でリリース作業を実施。本番環境でデプロイ後、システムの一部機能で正常性が確認できない事態が発生しました。

バックエンドはDockerで開発を行っているため、デプロイ時にdocker compose buildでビルドを毎回行っています。デプロイ自体は成功しているため、ライブラリのバージョンアップが関係しているのではないかと予想していましたが、のちに調査が難航することになるとは、このときは予想していませんでした。。

当該事象発生時は原因究明に至らなかったため、切り戻しを実施し、リリース作業は中断。翌日に原因調査を行いました。

question_head_gakuzen_boy.png

原因調査

前提として本番環境と開発環境で使用していたソースは、一部機能をマージしてないなど環境差異は発生していましたが今回発生した事象に関係はありません。

調査を開始し、開発環境で事象を再現させるために確認を行いましたが、同様の事象は発生しませんでした。その後、本番環境で使用したソースを開発環境でデプロイすると事象が再現しました。

開発環境で事象再現後、デバッグするために本番環境で使用したソースの不具合が発生している箇所にconsole.log(e)でログ出力する様にしてデバッグを行いました。

不具合が発生している箇所に対するAPIのリクエストを実行し、サーバ側のログを確認すると、データベースのあるテーブルのカラムが見つからないと言うエラーメッセージが出力されていました。

仮説としてプログラムで利用していたORMライブラリのバージョンが上がったため、今まで許容していたデータベースに対する接続がエラーになっているのではないかという考えに辿りつきました。

animal_chara_computer_azarashi.png

解決方法

本番環境で稼働中のコンテナで生成されたyarn.lockファイルと、開発環境でデプロイしたコンテナのyarn.lockファイルのORMライブラリのバージョンを比較すると、開発環境のコンテナのマイナーバージョンが1桁だけ上がっていることを確認しました。

検証としてpackage-lock.jsonのORMライブラリのバージョンを、本番環境で稼働中のコンテナで生成されたバージョンと同じバージョンに固定すると、事象が再現しないことが確認できました。

よって暫定対応としては、ORMのライブラリのバージョンを固定しないことで一旦は解決しましたが、今後の運用として色々と課題を認識しました。

shinpai_man.png

DevOps

DevOps観点で感じた課題について以下に記載します。

※本記事の内容は、あくまで考え方の一例であり、必ずしも全ての考え方がシステムに適合したり、ここに書いている内容で満たされている訳ではありません。

  • ライブラリのバージョン固定
    保守性を高める場合はライブラリのバージョンを上げないように固定することが望ましいですが、セキュリティとトレードオフになります。また、バージョンアップする場合は確認の工数もかかります。npm outdatedコマンドを実行すると、現在インストールされているバージョン、現在のバージョン指定でインストールされる最新バージョン、リリースされている最新バージョンが表示されます。

  • テストの再現性
    当たり前ですが極力環境差異をなくしたテスト方法の考案及びテスト環境を構築し、テストを実施することが望ましいです。※参考:3.6 本番環境とテスト環境の差異に関する教訓(T6)

  • 本質的なアプローチ
    今回の様な事象は技術的な手段で解決する以前に、開発や運用ポリシー等を定義していればこの様なリスクを軽減する可能性は上がります。

おわりに

本事象を通して改めて学んだのは、プログラムは数字1桁が変わるだけで動かなくなるという恐ろしさと、DevOpsの重要性です。

DevOpsは文化です。DevOpsは人が作る必要があるため、言うだけは簡単ですがシステムのあるべき姿を計画し、実行して継続することは大変です。

この失敗を次に生かしてシステム開発のライフサイクルを短縮し、ソフトウェア品質の高い継続的デリバリーを実現していきたいと思いました。

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

ログファイルからをバッチ処理を行う旧世代アプリケーションをサイドカーパターンとService Discoveryを使ってコンテナ内ロギングをする

概要

Dockerコンテナでアプリケーション構築するメリットは皆さんご周知ではあると思いますが、EC2でアプリケーションを公開していてECSなどのコンテナ基盤に乗り換えた時に、EBSやEFS等のlinuxファイルシステムに依存している部分をコンテナ上でどうするかという問題に直面します。

今回はその問題のうち、アクセスログファイル等を集計してDBに入れたいというありがちな問題をService DiscoveryとFluentdコンテナのサイドカーパターンで解決する手法を実践します。

そもそもなぜコンテナ内のファイルシステムに保持してはいけないか

Dockerfile 記述のベスト・プラクティスによると

Dockerfile が定義するイメージによって生成されるコンテナは、できる限り "はかないもの"(ephemeral)と考えておくべきです。 "はかない" という語を使うのは、コンテナが停止、破棄されて、すぐに新たなものが作り出されるからです。 最小限の構成や設定があれば稼動できます。

とあり、更にGCPのコンテナ運用のベストプラクティスによると、

初めてコンテナを試している場合、従来のサーバーのようにコンテナを扱わないでください。たとえば、実行中のコンテナ内でアプリケーションを更新したり、脆弱性が発生したときに実行中のコンテナにパッチを適用したりしたくなるかもしれません。

コンテナは基本的に、このような処理に対応するように設計されていません。コンテナは、ステートレスかつ不変になるように設計されています。

コンテナは基本的に、このような処理に対応するように設計されていません。コンテナは、ステートレスかつ不変になるように設計されています。
とあり、コンテナ内では状態を持たない = ステートレス であることがかなり推奨されています。
コンテナ内で作られたファイルをコンテナ内で持ってしまうと、コンテナが破棄され次世代のコンテナが立ち上がった際に生成したファイルが無いので実質欠損するという事態が起こりえます。
これを回避するためにデータストアに格納することが推奨されていますが、今回はDockerの永続化Volumeを使ってデータを退避させます。

コンテナ基盤を使って運用するときの普通のロギング

ECS、kubernetesなどのコンテナ基盤を使う場合、Dockerの標準ログドライバーを使うことが推奨されています。
主に、docker logskubectl logsで見れる標準出力のログをどこかに集約させるという手法です。
大体各種クラウドにはコンテナ基盤に付随してロギングを集約させるマネージドサービスが搭載されていると思うのでそれを使ってデータストアに入れるパターが王道だと思います。
ただ、これらはアプリケーション側でログ出力の整備を行わなければ成立しません。今回はその整備にコストがかかる場合、既存のロギングシステムを残しつつ、コンテナ環境でどう再現するかの手法です。

構成図

ecs-logging.png

コンポーネント

App Serviceの構築

メインのアプリケーションコンテナは複数コンテナ存在し、Fluentdのログコンテナは単一コンテナとしてログを集約させます。
App Serviceは通常通りnginx containerからunix socketsを介してapp containerに接続します。これに関してはこちらの記事を参照して構築していきます。
https://qiita.com/na-o-ys/items/1a863419e1f6c3063ace
App Serviceに関してはもう構築できている前提で話を進めていきます。

Log Serviceの構築

Log Serviceですがこちらは別サービスになっているのでscalingはせず、単一サービスとして構築します。
まず、Log Service用のタスクはport mappingは指定せず、Dockerfileでコンテナ側でのみportを開いてください。

"portMappings": [],
"networkMode": "awsvpc",

単一サービスですのでタスクの数は1、最小ヘルス率は0、最大率は100としてタスクの重複を許さないようにします。
スクリーンショット 2020-07-10 4.20.49.png
それと、今回はタスクのnetworkmodeはawsvpcに設定してください。

続いてサービス検出の設定ですが、名前空間名は好みで変えても良いですが、慣習としてxxx.local xxx.internalという名前空間が使われやすいです。
サービスの検出名も好みで良いですが、分かりやすくfluentdのコンテナ名にします。
スクリーンショット 2020-07-10 4.37.01.png

private DNSレコードは今回はAレコードを作成してください。
スクリーンショット 2020-07-10 4.37.08.png
注意点としてタスクのnetworkmodeがawsvpcじゃない場合Aレコードが作成できないと思います。
代替としてSRVレコードが用意されていますがこちらは動的ポートマッピングを使用する為、既存のログプラグインで対応できない可能性があります。
awsvpcはENIをアタッチされてるのでAレコードからportを指定して接続ができるようになります。
ENIをアタッチする関係上インスタンスを制限されるデメリットもありますが、ネットワークパフォーマンスの観点からもECS全体でawsvpcが推奨されます。

以上でサービスを構築するとService Discoveryによるprivate DNSでのコンテナアクセスが可能になります。
スクリーンショット 2020-07-10 5.05.51.png

タスク上でport mappingせずともdnsとportを指定して通信ができるようになったかと思います

root@21454022290b:/# dig fluentd.local

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-9.P2.amzn2.0.4 <<>> fluentd.local
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;fluentd.local. IN  A

;; ANSWER SECTION:
fluentd.local. 10   IN  A   172.31.0.54

;; Query time: 1 msec
;; SERVER: 172.31.0.2#53(172.31.0.2)
;; WHEN: 木  7月 09 20:15:59 UTC 2020
;; MSG SIZE  rcvd: 60

ログプラグインでもportを指定して接続ができるようになっているかと思います。

host: fluentd.local
port: 24224

これでログ集約サーバーの出来上がりです。

サイドカーパターンでログファイルを処理する

fluentdにより生成されたログファイルを用いてbatch containerで処理したい場合、サイドカーパターンでvolumeを共有して永続化する必要があります。

まずfluentdのDockerfileでvolumeのpathを指定してあげます。

VOLUME /fluentd/log/xxx

注意点はコンテナ内の実行ユーザーによってはvolumeディレクトリに書き込めない場合があるので、適宜書き込み権限を追加してください。

続いて、batchをサイドカーパターンでvolume共有したタスクを用意します。

[
  {
    "name": "fluentd",
    "image": "xxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/xxx-fluentd:e6767fd9",
    "cpu": 400,
    "memoryReservation": 400,
    "essential": true
  },
  {
    "name": "batch",
    "image": "xxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/xxx-batch:e6767fd9",
    "cpu": 400,
    "memoryReservation": 400,
    "essential": true,
    "volumesFrom": [
      {
        "readOnly": false,
        "sourceContainer": "fluentd"
      }
    ],
    "dependsOn": [
      {
        "containerName": "fluentd",
        "condition": "START"
      }
    ]
  }
]

ポイントはvolumesFromを指定してあげて書き込み処理をしたい場合はreadOnly: falseにすることです。
念のため、もしfluentd containerの起動が遅れた状態でにバッチ処理が走らないようにdependsOnで起動を待つ指定もしておきます。
また、batchコンテナ内のユーザーにも書き込み権限を追加するようにしてください。

今回自分が実践したbatchはcronで回すタイプだったのでcron -fで定期実行していますが、何かしらのトリガーで無事ログファイルのbatch処理が正常に走れば完成です。

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

docker-compose.ymlのbuild設定はとりあえずcontextもdockerfileも埋めとけって話

docker-composeを使った開発では以下の2つのディレクトリ構成になっていることが多いです。

サービスディレクトリ直下にDockerfile
.
├ app
│ ├ Dockerfile
│ └ ...その他ファイル群
├ api
│ ├ Dockerfile
│ └ ...その他ファイル群
├ nginx
│ ├ Dockerfile
│ └ ...その他ファイル群
└ docker-compose.yml
dockerディレクトリ下にサービス毎にDockerfile
.
├ app/
├ api/
├ nginx/
├ docker
│ ├ app
│ │ └ Dockerfile
│ ├ api
│ │ └ Dockerfile
│ └ nginx
│   └ Dockerfile
└ docker-compose.yml  

Dockerの コンテキスト という概念を知っていないと、ディレクトリ構成が違うだけで何度もコンテキスト周りのエラーで悩まされることがあります(1敗)。
なので自分的結論を出してみました。

TL;DR

docker-compose を使った開発では

docker-compose.yml
version: "3"
services:
  nginx:
    build: ./docker/nginx/

のようにDockerfileがあるディレクトリを指定するだけでなく

docker-compose.yml
services:
  nginx:
    build:
      context: .
      dockerfile: ./docker/nginx/Dockerfile

のようにコンテキストをルートディレクトリに指定して、Dockerfileの場所も直接指定しておけばおk

Dockerの「コンテキスト」とは?

docker build コマンドを実行したときの、カレントなワーキングディレクトリのことを ビルドコンテキスト(build context)と呼びます。 デフォルトで Dockerfile は、カレントなワーキングディレクトリにあるものとみなされます。 ただしファイルフラグ(-f)を使って別のディレクトリとすることもできます。 Dockerfile が実際にどこにあったとしても、カレントディレクトリ配下にあるファイルやディレクトリの内容がすべて、ビルドコンテキストとして Docker デーモンに送られることになります。

Dockerfile 記述のベストプラクティス

これをさらに要約すれば 「docker buildコマンドを実行した場所」ってことですね。

docker build コマンドを実行した場所ってことなので、docker buildコマンドはDockerfileがあるディレクトリで実行すれば問題なさそうですね。

しかし、docker-compose コマンドを使って開発している場合はどうでしょうか?
Dockerfileがあるディレクトリでコマンドを実行することってほとんど無いと思います。その場合はコンテキストについてどう考えればいいのでしょうか?

サービス直下にDockerfileを置く場合

例として「Laravel, Nginx」というよくあるプロジェクトの構成で考えてみます。
ディレクトリ構成は以下の様になります。

.
├ api
│ ├ Dockerfile
│ ├ app
│ ├ bootstrap
│ └ ...その他のLaravelファイル
├ nginx
│ ├ Dockerfile
│ └ default.conf
└ docker-compose.yml

このディレクトリ構成の場合、api/Dockerfilenginx/Dockerfileのコンテキストはそれぞれどこになるか分かりますか?
docker buildコマンドを実行するapi/nginx/ディレクトリ?

nginx/ディレクトリがコンテキストだとするとnginx/Dockerfileは以下のようになります。

nginx/Dockerfile
FROM nginx:1.18-alpine
ADD ./default.conf /etc/nginx/conf.d/default.conf

RUN mkdir -p /var/www/public
ADD ../api/public /var/www/public

以下の1文に注目してください。コンテキストが nginx/なのに、 ../api/public で分かる通り、コンテキストのディレクトリから外れたファイルを参照していますね。

nginx/Dockerfile
ADD ../api/public /var/www/public

このまま実行すると

ERROR: Service 'php' failed to build: COPY failed: stat /var/lib/docker/tmp/docker-builder115741816/api: no such file or directory

のようなエラーが出ます。

Dockerはコンテキスト(カレントディレクトリ)の外のファイルにはアクセスできない仕様なのです。そこら辺に関しては以下の記事で詳しく説明されています。

https://qiita.com/toshihirock/items/c85f3eb5f4752b15ca3d

ではどうやってnginx/のコンテキストからapi/のファイルにアクセスすればいいのでしょうか?
答えは簡単です。

コンテキストをルートディレクトリにすればいいのです

docker-compose.ymlで「コンテキスト」と「Dockerfileのある場所」を直接指定してみましょう。

docker-compose.ym;
version: "3"
services:
  nginx:
    build:
      context: .
      dockerfile: ./nginx/Dockerfile
    ports:
      - 8080:80
    depends_on:
      - php
  php:
    build:
      context: .
      dockerfile: ./api/Dockerfile
    ports:
      - 9000:9000

コンテキストはどちらのサービスも

build:
      context: .

docker-compose.ymlがあるルートディレクトリに設定。

Dockerfileの場所は

dockerfile: ./nginx/Dockerfile
dockerfile: ./api/Dockerfile

でそれぞれ指定。

dockerディレクトリにDockerfileをまとめた場合

では次にdocker というディレクトリを作って、その中に各サービスのDockerfileをまとめた構成を考えてみます。

.
├ api
│ └ Laravelのファイル群
├ nginx
│ └ default.conf
├ docker
│ ├ php
│ │ └ Dockerfile
│ └ nginx
│   └ Dockerfile
└ docker-compose.yml

先ほどと同様にコンテキストを docker/phpdocker/nginxと考えた場合、どうやってもうまくいきません。
このディレクトリ構成の場合は、そもそもDockerfileからコンテキスト外のサービスのファイル群が入っている api/nginx/に一切アクセスできません。

ここでも同様docker-compose.ymlでコンテキストをルートディレクトリに、Dockerfileの位置も直接指定する必要がありそうです。

docker-commpose.yml
version: "3"
services:
  nginx:
    build:
      context: .
      dockerfile: ./docker/nginx/Dockerfile
    ports:
      - 8080:80
    depends_on:
      - php
  php:
    build:
      context: .
      dockerfile: ./docker/api/Dockerfile
    ports:
      - 9000:9000

注意点

ルートディレクトリをDockerのコンテキストにすることで、Dockerfileはどんなファイルにもアクセスできるようになりました。
一方で、build時はその分Dockerデーモンという奴にそれだけ多くのファイルを送ることになるので遅くなることがあるようです。

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

Visual Studio Code で Nuxt.js を使った Docker コンテナ内での開発

はじめに

以前、環境を汚さず(選ばず)Nuxtプロジェクトを作成しGitHub Pagesで公開するまでの一部始終 という記事を書きました。
その後、より簡単にNuxtの開発環境を作れないかと何回かやっているうちに、
Visual Studio Code をうまく使えばよりシンプルにできることがわかってきたので、再度まとめました。
Nuxtのバージョンが上がってプロジェクト作成時の設定が若干変わっています。


事前準備

Docker, Visual Studio Codeをインストールしておきます。

これからインストールする方は以下を参考にしてください。

Windows 10 Home に Docker for Desktop をインストールする手順

Visual Studio Code のインストール手順(Windows)

※今回は Windows 10 Home 環境で作業していますが、Docker, Visual Studio Code が入っていればどのOSでも同じようにできるはずです。

今回の Nuxt.js のバージョンは 2.13.3 です。


Visual Studio Code の起動

Visual Studio Code を起動します。

image.png


プロジェクトフォルダの作成

メニュー File / Open Foder... を選択し、プロジェクト用フォルダを作成して開きます。

image.png

今回は C:\dev\nuxt_in_docker というフォルダを作成しました。
image.png

Welcome ページは不要ですので × ボタンで消します。
image.png

image.png


Dockerファイルの作成

ファイル作成ボタンimage.pngを押し、 Dockerfile を作成します。

image.png


Dockerfile に以下の内容を入力して保存します。

Dockerfile
FROM node:alpine
ENV CHOKIDAR_USEPOLLING=true NUXT_TELEMETRY_DISABLED=1
RUN apk update && apk add git

1行目では、apline OS上に node がインストールされた公式の Docker イメージを使うよう指定しています。
2行目では、Nuxt で開発する際の自動リロードと、統計情報参加の応答を環境変数で指定しています。
3行目では、Docker コンテナ内で Git を使えるようインストールしています。

image.png


Remote Development 拡張機能をインストール

Extensions image.pngに切り替えて、Remote Development を検索してインストールします。

(インストール済みなら何もしなくてOKです。)

image.png


コンテナ開発モードに切り替える

左下の Open a remote window ボタンをimage.png押して Remote-Containers: Reopen in Container を選択します。

image.png

つづけて、From 'Dockerfile' を選択します。

image.png

しばらく待つと左下の表示が image.png に変わります。
これで、Docker コンテナ内で開発する準備が整いました。

Vue開発用拡張機能をインストール

devcontainer.json が表示されるので、extentions に Vuter を追加し上書き保存します。

※Vuter は vue ファイルや js ファイル、スタイルシートのコードハイライトや、自動補完、構文チェックを行ってくれる拡張機能です。

devcontainer.json(変更前)
    "extensions": []
devcontainer.json(変更後)
    "extensions": ["octref.vetur"]

image.png


変更を反映させるために、左下の Open a remote window ボタンをimage.png押して Remote-Containers: Rebuild Container を選択します。

image.png


拡張機能を見ると、vuter がインストールされているのが確認できます。
image.png

Nuxtプロジェクト作成

メニュー Terminal / New Terminal を選択します。

image.png

Docker コンテナ内でターミナルを開いたことになるので、コマンドプロンプトではなくシェルになります。
image.png


ターミナル内で、Nuxtプロジェクトを作成コマンドを実行します。

TERMINAL
yarn create nuxt-app

image.png

実行途中で、プロジェクト作成時の各種設定を入力していきます。


プロジェクト名入力
? Project name: nuxt_in_docker

プロジェクト名を聞いてきますが、デフォルトでフォルダ名と同じに設定されていてそのままでいいので Enter を押します。


開発言語選択
? Programming language: JavaScript

JavaScript か TypeScript を選択できます。今回は JavaScript にしますので、そのまま Enter を押します。


パッケージ管理選択
? Package manager: Yarn

yarn か npm を選択できます。今回は yarn にしますので、そのまま Enter を押します。


sh:UI フレームワーク選択
? UI framework: (Use arrow keys)

下記11種類から選択できますが、今回は使用しない(None)ので、そのまま Enter を押します。

  1. Ant Design Vue
  2. Bootstrap Vue
  3. Buefy
  4. Bulma
  5. Element
  6. Framevuerk
  7. iView
  8. Tachyons
  9. Tailwind CSS
  10. Vuesax
  11. Vuetify.js

導入モジュール選択
? Nuxt.js modules: (Press <space> to select, <a> to toggle all, <i> to invert selection)

下記3つを選択できますが、後からでも追加できるので、そのまま Enter を押します。

  1. ◯ Axios
  2. ◯ Progressive Web App (PWA)
  3. ◯ Content

構文チェックツール選択
? Linting tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)

下記4つを選択できますが、Vuter である程度カバーできるので今回はそのまま Enter を押します。

  1. ◯ ESLint
  2. ◯ Prettier
  3. ◯ Lint staged files
  4. ◯ StyleLint

テストフレームワーク選択
? Testing framework: Jest

下記3つから選択できます。後からも追加できますが、設定が若干面倒ですので、今回は Jest を入れておきます。
↓キーで Jest を選択して Enter キーを押します。

  1. Jest
  2. AVA
  3. WebdriverIO

レンダリング方式
? Rendering mode: Universal (SSR / SSG)

Universal (SSR / SSG) か Single Page App (SPA) を選択できます。

今回は最終的に静的な html, js, css を生成するので、 Universal を選びます。そのまま Enter を押します。
※後から設定を変更することも可能です。


デプロイ方式選択
? Deployment target: Static (Static/JAMStack hosting)

作成したものをどのようにに動作させるかを選択します。
Server (Node.js hosting) は、Node.js のサーバで動作させます。
Static (Static/JAMStack hosting) は、JAM(JavaScript, API, Markup)=通常のWebサーバで動作させます。
今回は Static を選択し、Enter を押します。


開発ツール選択
? Development tools: jsconfig.json (Recommended for VS Code)

下記2つを選択できます。 Visual Studio Code 用におすすめされているので、
jsconfig.json を選択し、Enter キーを押します。

  1. ◯ jsconfig.json (Recommended for VS Code)
  2. ◯ Semantic Pull Requests

作成完了になるまでしばらく待ちましょう。

作成完了
?  Successfully created project nuxt_in_docker

  To get started:

        yarn dev

  To build & start for production:

        yarn build
        yarn start

  To test:

        yarn test

Done in 186.42s.

Git管理開始

gitを初期化し、ユーザ名とメールアドレスを登録します。
※ユーザ名、メールアドレスは自分のものに置き換えて入力してください。

TERMINAL
git init
git config user.name ユーザ名
git config user.email メールアドレス

初回コミット

Source Control image.png に切り替えて、コミットします。

image.png
コミットコメント欄に first と入力し、コミットボタンimage.pngを押します。

ステージングに入れてないと確認が出ますが、全ファイルをコミットするのでYesを選択します。
image.png

以下の表示が出る場合は、ユーザ名、メールアドレスが正しく登録されていませんので、再度登録コマンドを実行してください。
image.png


開発サーバを起動

開発サーバを起動します。

Exploer image.png に切り替え、下のほうにある NPM SCRIPTS を開き、dev の右側の三角ボタンimage.pngを押します。

しばらく待つと、 Listening on: http://localhost:3000/ と表示されます。
これで開発サーバが起動しました。

image.png

ポート設定

ブラウザで表示できるようにするために、Docker 内のポートとローカルポートを接続します。

Remote Exploer image.png に切り替えます。

3000番ポートが表示されているので、右の追加ボタンimage.pngを押します。

image.png

以下の画面が出た場合は「アクセスを許可する」ボタンを押します。

image.png

これで Docker 内の 3000 番ポートと、ローカルの 3000 番ポートが接続され、
ブラウザで動作確認ができます。

image.png


ブラウザで画面を確認

Open in Brower ボタンimage.pngを押します。

トップ画面が表示されます。
image.png


タイトルを変更

pages/index.vue を開きます。

image.png

nuxt_in_docker の文字を Nuxtはじめました に書き換えて上書き保存します。

image.png

保存するとブラウザの表示が自動的に切り替わります。

image.png


テストを実行

NPM SCRIPTS 内の test の右の三角ボンタンを押します。
image.png

しばらく待つとテスト結果とカバレッジが表示されます。
image.png


テストを追加

index.vue のテストを追加してみます。

test/Logo.spec.js をCtrlドラッグでコピーします。
image.png

ファイル名を index.spec.js に変更します。
image.png

Logo の部分を index に書き換えて上書き保存します。
image.png

再度テストを実行します。

すると以下のように Logo コンポーネントが正しく登録されていないと出ます。
image.png


警告が出ないうように修正

警告を消すために、index.vue の <script>タグ内を記述します。
image.png

変更前
<script>
export default {}
</script>
変更後
<script>
import Logo from "@/components/Logo.vue";
export default {
  components: {
    Logo
  }
};
</script>

再度テストを実行します。

image.png

警告が消えてきれいに実行できました。

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

VisualStudioCodeでNuxt.jsを使ったDockerコンテナ内での開発

はじめに

以前、環境を汚さず(選ばず)Nuxtプロジェクトを作成しGitHub Pagesで公開するまでの一部始終 という記事を書きました。
その後、より簡単にNuxtの開発環境を作れないかと何回かやっているうちに、
VisualStudioCodeをうまく使えばよりシンプルにできることがわかってきたので、再度まとめました。
Nuxtのバージョンが上がってプロジェクト作成時の設定が若干変わっています。

事前準備

Docker, Visual Studio Codeをインストールしておきます。

これからインストールする方は以下を参考にしてください。

Windows 10 Home に Docker for Desktop をインストールする手順

VisualStudioCodeのインストール手順(Windows)

※今回は Windows 10 Home 環境で作業していますが、Docker, VisualStudioCode が入っていればどのOSでも同じようにできるはずです。

今回の Nuxt.js のバージョンは 2.13.3 です。


VisualStudioCodeを起動します。

image.png


メニュー File / Open Foder... を選択し、プロジェクト用フォルダを作成して開きます。

image.png

今回は C:\dev\nuxt_in_docker というフォルダを作成しました。
image.png

Welcome ページは不要ですので × ボタンで消します。
image.png

image.png


ファイル作成ボタンimage.pngを押し、 Dockerfile を作成します。

image.png


Dockerfile に以下の内容を入力して保存します。

FROM node:alpine
ENV CHOKIDAR_USEPOLLING=true NUXT_TELEMETRY_DISABLED=1
RUN apk update && apk add git

1行目では、apline OS上に node がインストールされた公式の Docker イメージを使うよう指定しています。
2行目では、Nuxt で開発する際の自動リロードと、統計情報参加の応答を環境変数で指定しています。
3行目では、Docker コンテナ内で Git を使えるようインストールしています。

image.png

Extensions image.pngに切り替えて、Remote Development を検索してインストールします。

(インストール済みなら何もしなくてOKです。)

image.png


左下の Open a remote window ボタンをimage.png押して Reopen in Container を選択します。

image.png

つづけて、From Dockerfile を選択します。

image.png

しばらく待つと左下の表示が image.png に変わります。
これで、Dockerコンテナ内で開発する準備が整いました。

devcontainer.json が表示されるので、extentions に vuter を追加し上書き保存します。

※Vuter は vue ファイルや js ファイル、スタイルシートのコードハイライトや、自動補完、構文チェックを行ってくれる拡張機能です。

変更前
    "extensions": []
変更後
    "extensions": ["octref.vetur"]

image.png

変更を反映させるために、左下の Open a remote window ボタンをimage.png押して Rebuild Container を選択します。

image.png

拡張機能を見ると、vuter がインストールされているのが確認できます。
image.png

メニュー Terminal / New Terminal を選択します。

image.png

Docker コンテナ内でターミナルを開いたことになるので、コマンドプロンプトではなくシェルになります。
image.png


ターミナル内で、Nuxtプロジェクトを作成コマンドを実行します。

yarn create nuxt-app

image.png

実行途中で、プロジェクト作成時の各種設定を入力していきます。


プロジェクト名入力
? Project name: nuxt_in_docker

プロジェクト名を聞いてきますが、デフォルトでフォルダ名と同じに設定されていてそのままでいいので Enter を押します。


開発言語選択
? Programming language: JavaScript

JavaScript か TypeScript を選択できます。今回は JavaScript にしますので、そのまま Enter を押します。


パッケージ管理選択
? Package manager: Yarn

yarn か npm を選択できます。今回は yarn にしますので、そのまま Enter を押します。


:UI フレームワーク選択
? UI framework: (Use arrow keys)

下記11種類から選択できますが、今回は使用しない(None)ので、そのまま Enter を押します。

  1. Ant Design Vue
  2. Bootstrap Vue
  3. Buefy
  4. Bulma
  5. Element
  6. Framevuerk
  7. iView
  8. Tachyons
  9. Tailwind CSS
  10. Vuesax
  11. Vuetify.js

導入モジュール選択
? Nuxt.js modules: (Press <space> to select, <a> to toggle all, <i> to invert selection)

下記3つを選択できますが、後からでも追加できるので、そのまま Enter を押します。

  1. ◯ Axios
  2. ◯ Progressive Web App (PWA)
  3. ◯ Content

構文チェックツール選択
? Linting tools: (Press <space> to select, <a> to toggle all, <i> to invert selection)

下記4つを選択できますが、Vuter である程度カバーできるので今回はそのまま Enter を押します。

  1. ◯ ESLint
  2. ◯ Prettier
  3. ◯ Lint staged files
  4. ◯ StyleLint

テストフレームワーク選択
? Testing framework: Jest

下記3つから選択できます。後からも追加できますが、設定が若干面倒ですので、今回は Jest を入れておきます。
↓キーで Jest を選択して Enter キーを押します。

  1. Jest
  2. AVA
  3. WebdriverIO

レンダリング方式
? Rendering mode: Universal (SSR / SSG)

Universal (SSR / SSG) か Single Page App (SPA) を選択できます。

今回は最終的に静的な html, js, css を生成するので、 Universal を選びます。そのまま Enter を押します。
※後から設定を変更することも可能です。


デプロイ方式選択
? Deployment target: Static (Static/JAMStack hosting)

作成したものをどのようにに動作させるかを選択します。
Server (Node.js hosting) は、Node.js のサーバで動作させます。
Static (Static/JAMStack hosting) は、JAM(JavaScript, API, Markup)=通常のWebサーバで動作させます。
今回は Static を選択し、Enter を押します。


開発ツール選択
? Development tools: jsconfig.json (Recommended for VS Code)

下記2つを選択できます。 Visual Studio Code 用におすすめされているので、
jsconfig.json を選択し、Enter キーを押します。

  1. ◯ jsconfig.json (Recommended for VS Code)
  2. ◯ Semantic Pull Requests

作成完了になるまでしばらく待ちましょう。

作成完了
?  Successfully created project nuxt_in_docker

  To get started:

        yarn dev

  To build & start for production:

        yarn build
        yarn start

  To test:

        yarn test

Done in 186.42s.

gitを初期化し、ユーザ名とメールアドレスを登録します。

※ユーザ名、メールアドレスは自分のものに置き換えて入力してください。

git init
git config user.name ユーザ名
git config user.email メールアドレス

Source Control image.png に切り替えて、コミットします。

image.png
コミットコメント欄に first と入力し、コミットボタンimage.pngを押します。

ステージングに入れてないと確認が出ますが、全ファイルをコミットするのでYesを選択します。
image.png

以下の表示が出る場合は、ユーザ名、メールアドレスが正しく登録されていませんので、再度登録コマンドを実行してください。
image.png

開発サーバ起動を起動します。

Exploer image.png に切り替え、下のほうにある NPM SCRIPTS を開き、dev の右側の三角ボタンimage.pngを押します。

しばらく待つと、 Listening on: http://localhost:3000/ と表示されます。
これで開発サーバが起動しました。

image.png

Docker内のポートとローカルポートを接続します。

Remote Exploer image.png に切り替えます。

3000番ポートが表示されているので、右の追加ボタンimage.pngを押します。

image.png

以下の画面が出た場合は「アクセスを許可する」ボタンを押します。

image.png

これで Docker 内の 3000 番ポートと、ローカルの 3000 番ポートが接続され、
ブラウザで動作確認ができます。

image.png

Open in Brower ボタンimage.pngを押します。

トップ画面が表示されます。
image.png


タイトルを変更してみる

pages/index.vue を開きます。

image.png

nuxt_in_docker の文字を Nuxtはじめました に書き換えて上書き保存します。

image.png

保存するとブラウザの表示が自動的に切り替わります。

image.png


テストを実行する

NPM SCRIPTS 内の test の右の三角ボンタンを押します。
image.png

しばらく待つとテスト結果とカバレッジが表示されます。
image.png

テストを追加する

index.vue のテストを追加してみます。

test/Logo.spec.js をCtrlドラッグでコピーします。
image.png

ファイル名を index.spec.js に変更します。
image.png

Logo の部分を index に書き換えて上書き保存します。
image.png

再度テストを実行します。

すると以下のように Logo コンポーネントが正しく登録されていないと出ます。
image.png

警告を消すために、index.vue の <script>タグ内を記述します。
image.png

変更前
<script>
export default {}
</script>
変更後
<script>
import Logo from "@/components/Logo.vue";
export default {
  components: {
    Logo
  }
};
</script>

再度テストを実行します。

image.png

警告が消えてきれいに実行できました。

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