20200803のdockerに関する記事は15件です。

Dockerコンテナを持ち歩こう

概要

USBメモリを使い、管理者権限一切不要でWindowsPCがあればどこでもDockerコンテナを動かせる環境を構築します。

USBメモリについて

USB3.0対応の速度の速いものを選ばないと書き込み速度に引っ張られて動作が遅くなります。

CrystalDiskMarkのランダム書き込み(右下2つ)の値が1.0を超えていないと辛いと思います(※体感には個人差があります)

ちなみに自分はI-O DATAのU3-MAX2/32Kを使っています。

多少嵩張ってもいいのならポータブルSSDにすれば不良品でもない限り速度面で問題は出ないはず。

32GBまでのUSBメモリの場合、初期状態では概ねFAT32でフォーマットされていますが、FAT32は1ファイル最大4Gまでという制限があり、1ファイルで構成されている仮想ストレージがすぐに足りなくなり書き込みエラーが発生するのでNTFSやexFATでフォーマットしなおす必要があります。

また性質上書き込みを大量に行うので最悪いつ壊れてもいいように対応はしておきましょう。

仮想化ソフトのインストール

Qemu

Dockerは(64bitの)Linux上でしか動きませんので、仮想化ソフトでLinuxを動作させる必要があります、仮想化ソフトにはQemuを使います。

Qemuはエミュレート速度はいまいちですが、管理者権限が必須な各種アクセラレーターを有効にしない状態で起動することができます。つまり、遅くてもいいなら管理者権限なしで起動することが可能です。

WSL2や他の仮想化ソフトは管理者権限が必須な上ポータブル運用はできませんし、ポータブル運用を想定したPortable-VirtualBoxは管理者権限が必須です。

アクセラレーターなしではGnome等のデスクトップ環境を動かすのは困難ですが、CUI(コマンドライン)環境ならそれなりに動きます。(※体感には個人差があります)
Docker界隈では基本的にUIはWebブラウザが担うのがほとんどなのでさほど問題ではないです。

32bitPC・OS上でも64bitPCをエミュレートできる点もポイント高いです。

ダウンロード・インストール

公式サイトからQemuのWindows版(32bit版または64bit版)をダウンロードします。

Windows版のQemuは管理者権限が必要なインストーラー形式でしか配布をしていないようなので、インストーラーの解凍に対応したUniversal Extractor2(直リンク)でUSBメモリに解凍します。

ちなみに管理者権限を使ってインストールをし、インストールされたファイルをUSBメモリにコピーしても使えます。

Linuxのインストール

Alpine Linux

QemuをUSBメモリにインストール(コピー)したら、仮想PCにLinuxをインストールします。

インストールするLinuxデストリビューションは64bit対応でDockerをインストールできるものなら何でもいいのですが、

個人的にはAlpine Linuxがオススメです。インストールが爆速です。Debian等のよく使われるLinuxデストリビューションをイチからインストールしようとすると、ただでさえ遅いQemu上では最小構成でも数時間は覚悟しないといけませんが、数分でインストールが終わります。

Alpine Linuxは誤解を恐れずざっくりいうと互換性を犠牲にして軽量化にこだわったデストリビューションで、サイズが小さいためDockerの公式イメージのベースとしてよく採用されており、Docker界隈ではよく目にします。

一部他のLinuxデストリビューションで使わているソフトウェアが使えないなど互換性に難がありますが、Alpine Linux本体はDockerホストに徹し、ソフトウェアは基本的にDockerコンテナ上で動かすという運用をすれば問題になりません。

isoダウンロード

公式サイトisoのダウンロードページがあるのでx86_64版をダウンロードします。

Standard(124M)でもいいのですが、仮想PC用のさらにサイズの小さいVirtual(40M)をお勧めします。

ダウンロードするとalpine-virt-3.12.0-x86_64.isoといった長いファイル名になるので、alpine.isoとかに変えておくと後が楽です。

インストール

Qemuは他の仮想化ソフトとは異なりすべてコマンドラインで設定・起動する仕組みになっています(GUIで動かすためのフロントエンドはいろいろありますが)

仮想ストレージファイルの作成

> qemu-img create -f qcow2 linux.qcow2 20G

最後の20Gは仮想ストレージファイルの最大容量になるので環境に合わせて変更しましょう。
いきなり20G全容量を確保するのではなく、最大容量に達するまで必要に応じてサイズが大きくなっていく仕組みになっています。

isoファイルをブートディスクにして起動

Qemuのオプションはドキュメントを見てください、自分は以下のように設定しています。

> qemu-system-x86_64.exe -display sdl -smp 2 -boot d -m 2048 -net nic,model=virtio -hda linux.qcow2 -cdrom alpine.iso

問題がなければウインドウが出てLinuxのブートを開始するはずです。ブートには1分から数分かかります。

インストール

ブートが終了するとコンソールのログイン画面が出てきますが、rootと入力してエンターを押すとパスワードなしでログインできます。

localhost login: root

ログインしたら、

# setup-alpine

でインストールを開始します。コマンドライン上でいくつか質問されるので、答えていくとインストールを始めます。

具体的にどんな内容なのかはここらへんを参考にどうぞ。長いので省略します。

インストールが終わったら

# poweroff

でシャットダウンします。

Linux起動・設定

起動

> qemu-system-x86_64.exe -display sdl -smp 2 -m 2048 -net nic,model=virtio -net user,hostfwd=tcp::22-:22,hostfwd=tcp::9000-:9000 -hda linux.qcow2

自分はこのようにして起動しています(一部を除く)。

「-net user,hostfwd=tcp::22-:22,hostfwd=tcp::9000-:9000」の部分で指定したポートを通じてQemu内Linux上のサーバーに接続できるようになります。ポートフォワーディングというらしい。
(※同一PCのローカル接続の話であって外部PCからの接続はWindowsファイアウォールやルータ等の関係でそのままでは出来ませんし管理者権限が必要です)

例えばこの場合だとlocalhost:22でWindowsホストではなく、Qemu内のLinuxで22番ポートを待ち受けしているサーバーに接続できるようになります。

ここではSSH用の22番とPortainer用の9000番を割り当てています。上記のように,でつないでいけば複数のポートを開くことができますが、すでに別のサーバーで待っているポートを指定するとQemu自体エラーで起動しないので注意してください。

ちなみに、Dockerコンテナ上のサーバーの接続にも有効です。つまり、Qemuの起動時に9000番ポートへの待ち受けを有効にしていれば、Linuxホストの9000番ポートを待ち受ける設定で起動したDockerコンテナにWindowsホストから9000番ポートで接続できるということです。

SSHの設定

インストール時同様にログイン画面が出たら、IDはroot、パスワードはインストール時に設定したパスワードでログインします。

Qemuのウインドウではコマンドのコピペが出来ず何かと不便なのでSSHを使えるようにします。

Alpine Linuxは最初からSSHサーバーが入っていますが(インストール時のSSHの質問でnoneと答えなかった場合)、SSHサーバーの仕様でそのままではrootユーザーでログイン出来ないようになっているので、ここでは手っ取り早く設定ファイルを追記してrootでログインできるようにします。

# echo "PermitRootLogin yes" >> /etc/ssh/sshd_config

さらにパスワードなしで運用する場合は次も入力します

# echo "PermitEmptyPasswords yes" >> /etc/ssh/sshd_config

設定ファイルを変更したらQemuを一度シャットダウンして再起動するかまたはSSHサーバーを再起動します

# service sshd restart

接続

最近のWindows10は標準でOpehSSHクライアントが入っていますが、そのまま使うとユーザーフォルダに.sshフォルダを作ってしまいポータブルではなくなってしまうので、以下のように設定ファイルを読み込まず、鍵のチェックをせず、KnownHostsファイルを残さないオプションをつけて起動します。

> ssh -F /dev/null -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null root@localhost

Dockerインストール

Alpine Linuxはapkという独自のパッケージマネージャーを持っていますが、初期状態ではdockerをインストールできないので、インストールできるようにviで/etc/apk/repositoriesを編集します。

# vi /etc/apk/repositories

初期状態では2行目のcommunityリポジトリが#でコメントアウトされていますが、#を消して有効にします。

#/media/cdrom/apks
http://dl-cdn.alpinelinux.org/alpine/v3.12/main
http://dl-cdn.alpinelinux.org/alpine/v3.12/community
#http://dl-cdn.alpinelinux.org/alpine/edge/main
#http://dl-cdn.alpinelinux.org/alpine/edge/community
#http://dl-cdn.alpinelinux.org/alpine/edge/testing

保存したら、apkでdockerとdocker-composeパッケージをインストールします

# apk update
# apk add docker docker-compose

インストールが終わったらdockerを起動します。

# service docker start

起動時に自動で開始するように設定しておきます。

# rc-update add docker boot

ちゃんと動作しているかを確認する場合は(多分)そのために用意されているhello-worldイメージをダウンロードしてコンテナとして動作させてみます。

# docker run --rm hello-world

上手く行けば以下のような表示が出るはずです。

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete
Digest: sha256:49a1c8800c94df04e9658809b006fd8a686cab8028d33cfba2cc049724254202
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

Portainerのインストール

Dockerコンテナをすべてコマンドラインで管理するのが辛い場合は、Webブラウザ上でDockerコンテナを管理できるPortainerをお勧めします。

Dockerをインストール出来ていれば以下のコマンド1行でインストール完了です。

# docker run -d -p 9000:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer

インストール完了後、Webブラウザで http://localhost:9000 にアクセスすればPortainerのログイン画面が出てくるはずです。

セキュリティ

rootでの運用はこの場合はUSBメモリをPCに接続しQemuが動作している間しか機能せず、かつ通常ローカル接続しかできないのであまり問題にはなりませんが、基本的にはやってはいけない運用であることは覚えておきましょう。またUSBメモリの紛失盗難には気を付けましょう。

さいごに

これでDockerコンテナをUSBメモリで持ち歩く環境が完成しました。
自分が自由に管理できるPCがない人におすすめです。

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

dockerの超超基本からまとめる #2 ~とりあえず動かしてみよう~

はじめに

この記事はDocker初心者の私がなんとか自分なりにDockerを動かせるようになるまでの備忘録です。
内容に至らない点は多いと思いますが、生暖かい目で見守ってください。

前回までのあらすじ

前回: dockerの超超基本からまとめる #1 ~仮想環境とDocker~
Dockerとは?仮想環境とは?コンテナ?イメージ?
現状の認識についてまとめた。

今回の内容

なんとかしてDocker上でちょっと古いバージョンのpythonを動かしてみる。

開発環境

MacBook Pro (Catalina 10.15.6)
docker (2.3.0.4)

今回参考にしたリンク

DockerでPythonの開発環境を作成してみる その1

Docker動かしてみよう

dockerfileとは

めちゃくちゃわからん!!!
わからなさすぎて何がわからないかわからんぞ!!

とりあえずわかっていることを書こう。

  • dockerfileによってコンテナの中にどのイメージを持ってくるか決まっている

これだけしかわからない。

では今回使うdockerfileをみてみよう。

dockerfile
# ベースイメージ
FROM python:3.5.9

# pipをアップグレード
RUN pip install --upgrade pip

# 作業ディレクトリ作成
WORKDIR /workdir

# ポート
EXPOSE 8080

うーん、見た感じ大文字がコマンドでその後に色々打ち込んでいる様子?
dockerの公式ドキュメントを参考に解読してみます。

コマンド 意味
FROM ベースとなるイメージを選択する
RUN 現在のイメージの上に任意のコマンドを実行する
WORKDIR 作業用のディレクトリを作成する
EXPOSE listenするポート番号を設定しておく

わかったような、わからないような。

今回のdockerfileではpythonの3.5.9を使おうとしている。
そして、なぜかpipをアップデートして、作業用のディレクトリを作成して、なぜかポートを開けている、と。

やっていることはわかったが、なんのためにやっているのかはよくわからない。
とりあえず先に進もう。

dockerをbuildする

簡単に言ってくれますね。
dockerをbuildするとは一体なんぞや。

dockerがdockerfileの設定に基づいて、イメージを作ることをdocker buildと表現する。
先ほどのdockerfileによるとpythonの3.5.9のイメージが必要みたい。
docker imagesで現在の取得しているイメージの一覧を確認できる。

$ docker images
REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
python                               3.5.9               d97bc12bd39e        2 days ago          910MB

pythonの3.5.9がきちんと取得できていることがわかる。

ここまででbuildの準備ができたので、早速buildをしてみる。
コマンドはdocker build [-t コンテナの名前] {dockerfileのある場所}だ。
コンテナの名前は設定しないとかっこいい名前を勝手につけてくれるが、使いにくいので自分で名前をつけよう。

$ docker build -t pythondev .
Sending build context to Docker daemon  2.048kB
Step 1/4 : FROM python:3.5.9
 ---> d97bc12bd39e
Step 2/4 : RUN pip install --upgrade pip
 ---> Running in 525799f95f6d
Requirement already up-to-date: pip in /usr/local/lib/python3.5/site-packages (20.2)
Removing intermediate container 525799f95f6d
 ---> c2d7a316ec79
Step 3/4 : WORKDIR /workdir
 ---> Running in eeb6a9396ea6
Removing intermediate container eeb6a9396ea6
 ---> 810f2c4617a1
Step 4/4 : EXPOSE 8080
 ---> Running in acd9e412eea5
Removing intermediate container acd9e412eea5
 ---> 5c48c0526e48
Successfully built 5c48c0526e48
Successfully tagged pythondev:latest

何しているか細かいことはよくわからないが、dockerfileの記述通りの処理をしてくれてる感じがする。

$ docker images 
REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
pythondev                            latest              5c48c0526e48        3 minutes ago       916MB

きちんとイメージが作成されていることも確認する。
これでpythonの3.5.9の環境のイメージが完成。

検証

現在取得できていないpython3.5.8にdockerfileを書き換えてbuildしてみたところ、どうやら足りないイメージは自動で落としてくれるみたい。便利ですね。

$ docker build .
Sending build context to Docker daemon  2.048kB
Step 1/4 : FROM python:3.5.8
3.5.8: Pulling from library/python
c7b7d16361e0: Pull complete 
b7a128769df1: Pull complete 
1128949d0793: Pull complete 
667692510b70: Pull complete 
bed4ecf88e6a: Pull complete 
94d1c1cbf347: Pull complete 
765d0dc09bbf: Pull complete 
65bf6e648924: Pull complete 
66c62c8268bd: Pull complete 
Digest: sha256:46dbbb6c23a9069da0fae6d5afb74483e0344c1fbc796a18507c52517b5438db
Status: Downloaded newer image for python:3.5.8
 ---> 0688d5a54cf4

ついでなのでイメージの削除方法について別記事にまとめた。

dockerをrunする

buildをすることで作成したイメージを使って実際に使用するコンテナを作成していく。

$ docker run -it --name pythonwork pythondev
Python 3.5.9 (default, Jul 22 2020, 13:58:49) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> exit()
$ docker ps -a
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS                      PORTS                                      NAMES
c205807cc2eb        pythondev                   "python3"                43 seconds ago      Exited (0) 12 seconds ago                                              pythonwork

-itのオプションでコンテナの内部に入れるらしい(?)
--nameのオプションによって任意の名前がついたコンテナが作成されていることがわかる。
このコンテナにもう一回入るにはdocker start {コンテナ名}でコンテナを起動した上でdocker exec -it {コンテナ名} {コマンド}で入ることができる。

$ docker start pythonwork
pythonwork
$ docker exec -it pythonwork bash
root@c205807cc2eb:/workdir# 

ここではコマンドにbashを使うことでshellコマンド打てる状態になっている。
さらにdockerfileで記述したworkdirのディレクトリに入っているのがわかる。

何はともあれ、これでdocker上でpython3.5.9が動いたぞ!

外部ファイルとの連携

だがしかし、これコーディングできないよね?
当然VScodeもvimもemacsも入っていない環境なので、ろくなコードが書けない。
そこで、外部ファイルとコンテナを同期する方法があるらしい。

$ docker run -it -v /Users/kyabe/python/bert/src:/workdir --name pythonwork pythondev /bin/bash

このコマンドを動かすとローカルの/Users/kyabe/python/bert/src/workdirをリンクさせることができる。

実際にコンテナの中身を見てみるとdockerfileが既に入っていることがわかる。

$ docker run -it -v /Users/kyabe/python/bert:/workdir --name pythonwork pythondev /bin/bash
root@dbc8113d1f3b:/workdir# ls
dockerfile

これでローカルで編集したコードをdocker上で動かせるようになった!

まとめ

自分でdockerの環境を作った

  • dockerfileを作成
  • buildしてイメージを作成
  • runでコンテナを作成
    • -itでそのまま中に入れる
  • exitで脱出
  • startで再開
  • このままだとコーディングできないので、ローカルのディレクトリとリンクさせた

わからないこと

  • dockerfile謎すぎ
  • -itとはなんぞ
  • なんでデフォルトでpython3が起動するんだ?
    • 多分docker ps -aでみたときのCOMMANDのところのコマンドが実行されているのかな
    • そしてこれはおそらくdockerfileのCMDなのかなっていう予想
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

docker レシピ vscode remote-conatainer + live share

vscode remote-development, vscode remote-container, docker, レシピ, live share

vscode remote-conatainerを使うときにlive shareでhostしようと思ったら、remote-container内にlive share extensionを入れなければなりません。しかもcontainerに依存するパッケージを導入する必要もあります。

以下のレシピを切り貼りして、自分の開発コンテナにlive share環境を導入しましょう!

.devconteinar/.devcontainer.json
// 略
    "extensions": [
        "ms-vsliveshare.vsliveshare"
    ]
}
Dockerfile
FROM debian # or ubuntu

# live share dependencies
# via: https://docs.microsoft.com/en-us/visualstudio/liveshare/reference/linux#debian--ubuntu
RUN apt-get update && apt-get install -y \
  libssl1.1 \
  libkrb5-3 \
  zlib1g \
  libicu[0-9][0-9] \
  gnome-keyring \
  libsecret-1-0 \
  desktop-file-utils \
  x11-utils \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

他のOSの場合: https://docs.microsoft.com/en-us/visualstudio/liveshare/reference/linux

残念ながら現在のbaseのrecommendedであるalpineでのそのもののコマンドは掲載されていない。
(やり方緩募)

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

GPU共有のためのAlibabaオープンソース、プラグイン可能なスケジューリングツールの紹介

本記事では、クラスタ内のGPUリソースの使用量を最適化する、Alibabaのオープンソースでプラグイン可能なGPU共有用スケジューリングツールを紹介します。

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

クラスタのスケジューリング:KubernetesのGPU共有

クラスタスケジューリングのためのGPU共有は、より多くのモデル開発や予測サービスにGPUを共有させることで、クラスタ内のNvidia GPU利用率を向上させることを目的としています。そのためには、GPUリソースの分割が必要です。GPUリソースは、GPUビデオメモリとCUDAカーネルスレッドで分割されます。一般的に、クラスタレベルのGPU共有は、主に次の2つのことを行います。

  1. スケジューリング

  2. アイソレーション:この記事では主にスケジューリングについて説明します。アイソレーションソリューションでは、ユーザーは特定のアプリケーション制限パラメータを渡す必要があります(例えば、TensorFlowのper_process_gpu_memory_fractionを使用するなど)。将来的には、Nvidia MPSをベースにしたオプションが利用可能になる予定です。GPUソリューションも計画されています。

GPUカードの細かな粒度のスケジューリングについては、Kubernetesコミュニティでは現在のところ良い解決策がありません。というのも、KubernetesのGPUなどの拡張リソースの定義では、整数粒度の加減算しかサポートしておらず、複雑なリソースの割り当てには対応していないからです。例えば、Pod AでGPUカードの半分を占有したい場合、現在のKubernetesアーキテクチャの設計では、リソース割り当ての記録と呼び出しは実装できません。ここで、Multi-Card GPU Shareは実際のベクトルリソースに関するものであり、Extended Resourceはスカラーリソースを記述しています。

そこで、Kubernetesの既存のワーキングメカニズムに依存したアウトオブツリー型のShare GPU Schedulingソリューションを設計しました。

  • 拡張リソース定義
  • スケジューラエクステンダ機構
  • デバイスプラグインの仕組み
  • Kubectl拡張機構 このShare GPU Scheduling Extensionの利点は、API Server、Scheduler、Controller Manager、Kubeletなどのコアコンポーネントに侵襲性のないKubernetesの拡張機能とプラグインの仕組みを利用していることです。これにより、ユーザーはコードをリベースしたり、Kubernetesのバイナリパッケージを再構築したりすることなく、異なるバージョンのKubernetesにこのソリューションを簡単に適用することができます。

ユーザーシナリオ

  • クラスタ管理者: "クラスタのGPU利用率を向上させたい。開発中は複数のユーザがモデル開発環境を共有する。”
  • アプリケーション開発者:"Volta GPU上で複数のロジックタスクを同時に実行できるようにしたい”

Goal

  • 利用者はAPIを介して共有リソースの申請を記述し、リソースのスケジューリングを行うことができること。

Non-Goal

  • 共有リソースの分離はサポートされていない。
  • オーバーセリングはサポートされていない。

設計原理

  1. 問題点を明確にし、設計を簡素化します。最初のステップではスケジューリングとデプロイのみを行い、その後にランタイムメモリの制御を実装します。
    多くの顧客は、マルチAIアプリケーションを同じGPUにスケジューリングできるようにしたいという明確な要件を持っています。彼らはアプリケーションレベルからメモリのサイズを制御することを受け入れ、gpu_options.per_process_gpu_memory_fractionを使用してアプリケーションのメモリ使用量を制御することができます。最初に解決しなければならない問題は、メモリをスケジューリングスケールとして使用することを単純化し、メモリのサイズをパラメータの形でコンテナに転送することです。

  2. 押し付けがましい修正をしない
    本設計では、拡張リソースの設計、スケジューラの実装、デバイスプラグインの仕組み、Kubeletの関連設計など、Kubernetesの以下の設計の核となる部分は変更しません。拡張リソースを再利用して、共有リソースのためのアプリケーションAPIを記述します。ユーザーがネイティブのKubernetes上で利用できるポータブルなソリューションを提供できるという利点があります。

  3. メモリベーススケジューリングとカードベーススケジューリングのモードは、クラスタ内で共存することができます。しかし、同一ノード内では互いに排他的であり、共存はできません。この場合、リソースはカード数またはメモリ数のどちらかで割り当てられます。

詳細設計

前提:

  1. Kubernetesの拡張リソースの定義はそのまま使用しますが、次元を測る最小単位がGPUカード1枚からGPUメモリのMiBに変更されています。ノードが使用するGPUが1枚カード16GiBのメモリで、それに対応するリソースが16276MiBだとします。

  2. シェアGPUに対するユーザーの需要は、モデル開発やモデル予測のシナリオにあります。したがって、この場合、ユーザが適用するGPUリソースの上限は1枚を超えることはできない、すなわち、適用されるリソースの上限は1枚です。

まず、我々のタスクは、2つの新しい拡張リソースを定義することです:1つ目はGPUメモリに対応するgpu-memで、2つ目はGPUカードの枚数に対応するgpu-countです。ベクトルリソースは、この2つのスカラーリソースで記述されており、これらを組み合わせることで、Share GPUをサポートする仕組みを提供します。基本的なアーキテクチャ図は以下の通り。

image.png

コア機能モジュール

  • GPU共有スケジューラエクステンダー:Kubernetesのスケジューラ拡張機構を利用して、グローバルスケジューラがフィルタリングしてバインドした際に、ノード上の1枚のGPUカードが十分なGPU Memを提供できるかどうかを判断し、その後のフィルタリングで割り当て結果を確認するためのバインド時のアノテーションを介して、GPU割り当て結果をPod Specに記録します。
  • GPU Share Device Plugin:ノード上のKubeletから呼び出されるDevice Pluginの仕組みを利用して、Scheduler Extenderのアロケーション結果に基づいてGPUカードを割り当てて実行します。

処理の詳細は以下の通りです。

  1. リソースレポート

GPU Share Device Pluginはnvmlライブラリを利用してGPUカードの枚数と各GPUカードのメモリを照会し、ノード上のGPUの総メモリ(数量メモリ)を拡張リソースとしてListAndWatch()を介してKubeletに報告します。そして、KubeletはそれをKubernetes API Serverに報告します。例えば、ノードに2枚のGPUカードがあり、各カードに16276MiBが含まれている場合、ノードのGPUリソースは16276 2 = 32552となり、ノード上のGPUカードの枚数が2枚であることも、ユーザーから見て追加のExtended Resourceとして報告されます。

  1. 拡張スケジューリング

GPU Share Scheduler Extenderは、Podへのgpu-memの割り当て中にPod Specにアノテーションの形で割り当て情報を予約し、この情報に基づいてフィルタリング時に各GPUカードに十分な利用可能なgpu-memの割り当てがあるかどうかを判断することができます。

2.1. デフォルトのKubernetesスケジューラは、すべてのフィルタアクションが実行された後、http経由でGPU Share Scheduler ExtenderのFilterメソッドを呼び出します。これは、デフォルトのスケジューラは、リソースの総量が需要を満たす空きリソースを持っているかどうかを判断することしかできず、拡張リソースを計算する際に、1枚のカードで需要が満たされているかどうかを具体的に判断することができないためです。そのため、1枚のカードに空きリソースがあるかどうかを確認するのは、GPU Share Scheduler Extenderに任されています。

以下の図を例に説明します。2枚のGPUカードを含む3ノードで構成されるKubernetesクラスタにおいて、ユーザーがgpu-mem=8138を申請すると、デフォルトのスケジューラーは全ノードをスキャンし、N1の残りのリソースが16276 * 2 - 16276 -12207 = 4069となり、リソース要求を満たしていないことが判明したため、N1ノードはフィルタリングアウトされます。

N2、N3ノードの残りリソースはともに8138MiBで、全体のスケジューリングの観点からはデフォルトスケジューラの条件を満たしています。このとき、デフォルトスケジューラは GPU Share Scheduler Extender に二次フィルタリングを委託しています。2次フィルタリングでは、GPU Share Scheduler Extenderは、シングルカードがスケジューリングの条件を満たしているかどうかを判断する必要があります。N2ノードの場合、8138MiBの利用可能なリソースを持っていることがわかりますが、各GPUカードから見た場合、GPU0とGPU1の利用可能なリソースは4069MiBしかなく、1枚のカードでは8138MiBの要求を満たすことができません。N3ノードも合計8138MiBの利用可能なリソースを持っていますが、これらの利用可能なリソースはすべてGPU0に属しており、シングルカードのスケジューリングの需要を満たしています。その結果、GPU Share Scheduler Extender のフィルタリングにより、精密な条件付きフィルタリングが可能となりました。

image.png

2.2. スケジューラは条件を満たすノードを見つけると、GPU Share Scheduler ExtenderのbindメソッドにノードとPodのバインドを委託します。ここで、Extenderは2つの操作を行う必要があります。

  • binpackポリシーに従ってノード内の最適なGPUカードIDを見つけること。ここでいう「ベスト」とは、同一ノード内の異なるGPUカードに対して、binpackポリシーを決定条件とし、残りリソースが少なく、条件を満たす空きリソースを持つGPUカードを優先的に選択し、PodのアノテーションにALIYUN_COM_GPU_MEM_IDXとして保存することを意味します。また、Pod のアノテーションには、Pod が適用した GPU メモリも ALIYUN_COM_GPU_MEM_PodALIYUN_COM_GPU_MEM_ASSUME_TIME として保存し、この時点で選択したノードに POD をバインドします。 注:ALIYUN_COM_GPU_MEM_ASSIGNEDのPodアノテーションも保存され、"false "に初期化されます。これは、スケジューリング中にGPUカードにPodが割り当てられていることを意味しますが、実際にはノード上にPodが作成されていないことを意味します。ALIYUN_COM_GPU_MEM_ASSUME_TIMEは割り当てられた時間を表します。

割り当てられたノード上に条件を満たすGPUリソースがない場合、スケジューラはこの時点でバインディングを実行せず、エラーを報告せずに直接終了します。デフォルトのスケジューラは、assumeがタイムアウトした後にリスケジュールを行います。

  • Kubernetes APIを呼び出して、ノードとPodのバインディングを実行する。 次の図に示すように、GPU Share Scheduler Extenderがgpu-mem 8138を持つPodを選択したノードN1にバインドすると、まずGPU0(12207)、GPU1(8138)、GPU2(4069)、GPU3(16276)の異なるGPUの利用可能なリソースを比較します。GPU2は、残りのリソースが要件を満たしていないために廃棄されます。条件を満たす他の3つのGPUのうち、空きリソースが条件を満たしている中でリソースの残量が最も少ないGPUカードがGPU1であるため、GPU1が選択される。

image.png

  1. ノード上での実行

PodがノードにバインドされているというイベントをKubeletが受信すると、Kubeletはノード上に実在のPodエンティティを作成します。この処理では、KubeletはGPU Share Device PluginのAllocateメソッドを呼び出し、AllocateメソッドのパラメータはPodが適用するgpu-memとします。Allocateメソッドでは、GPU Share Scheduler Extenderのスケジューリング決定に従って、対応するPodが実行されます。

  • このノードのGPU共有Podのうち、Pending状態でALIYUN_COM_GPU_MEM_ASSIGNEDがfalseになっているものがすべてリストアップされます。
  • ALIYUN_COM_GPU_MEM_POD(ポッドアノテーションの)とAllocate applicationsが同じ数のポッドが選択されます。複数のPodが条件を満たす場合、最も早いALIYUN_COM_GPU_MEM_ASSUME_TIMEを持つPodが選択されます。
  • ポッドアノテーションのALIYUN_COM_GPU_MEM_ASSIGNEDがtrueに設定され、ポッドアノテーションのGPU情報が環境変数に変換されてKubeletに戻され、真にポッドが作成されます。

image.png

関連プロジェクト

現在、プロジェクトはgithub.comでオープンソース化されています。

gpushar-scheduler-extender

gpushar-device-plugin

デプロイ

Deployment documentationを参照してください。

テストサンプル

  1. まず、aliyun.com/gpu-memを使用するアプリケーションを作成します。
apiVersion: apps/v1
kind: Deployment
metadata:
  name: binpack-1
  labels:
    app: binpack-1
spec:
  replicas: 1
  selector: # define how the deployment finds the pods it manages
    matchLabels:
      app: binpack-1
  template: # define the pods specifications
    metadata:
      labels:
        app: binpack-1
    spec:
      containers:
      - name: binpack-1
        image: cheyang/gpu-player:v2
        resources:
          limits:
            # MiB
            aliyun.com/gpu-mem: 1024

使用方法

Usage documentationを参照してください。

ビルド

ビルド方法を参照してください。

ロードマップ

  • オプションでNvidia MPSのサポートはDevice Pluginで利用可能です。
  • ソリューションは、kubeadmによって開始されたKubernetesクラスタに自動的にデプロイすることができます。
  • Scheduler Extenerの可用性が向上します。
  • GPU、RDMA、フレキシブルネットワークカードに対応した一般的なソリューションが提供されています。

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

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

Ubuntu 16.04がインストールされたAlibaba Cloud上で、Dockerを使用してNextcloudを設定する方法

このチュートリアルでは、Ubuntu 16.04をインストールしたAlibaba Cloud Elastic Compute Service (ECS)にNextcloudをインストールして設定します。

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

前提条件

  • Alibaba Cloud Elastic Compute Service (ECS)を有効にし、有効な支払い方法を確認する必要があります。新規ユーザーの場合は、新規アカウントで300ドル~1200ドル相当のAlibaba Cloudクレジットを獲得できます。ECSインスタンスのセットアップ方法がわからない場合は、このチュートリアルまたはクイックスタートガイドを参照してください。ECSインスタンスには、少なくとも1GBのRAMと1つのCoreプロセッサが必要です。
  • Alibaba Cloudから登録されたドメイン名。すでにAlibaba Cloudまたは他のホストからドメインを登録している場合は、そのドメインネームサーバーレコードを更新することができます。
  • ドメイン名は、あなたのAlibaba Cloud ECSのIPアドレスを指している必要があります。
  • Alibaba CloudのVNCコンソールまたはPCにインストールされているSSHクライアントにアクセスします。
  • サーバーのホスト名を設定し、root権限を持つユーザーを作成します。

サーバーの設定

パッケージのインストールを進める前に、以下のコマンドを使用してUbuntuシステムをアップデートしてください。このコマンドを実行するには、root 以外のユーザから sudo 権限でログインすることを忘れないでください。

# sudo apt update && sudo apt upgrade

Docker CEのインストールに対応したファイルを取得するためには、software-properties-commonパッケージが必要です。software-properties-commonをインストールするには、コマンドを実行します。

# sudo apt-get install software-properties-common -y 

Docker CEのインストールには、apt-transport-httpsが必要です。apt-transport-httpsをインストールするには、コマンドを実行します。

# sudo apt-get install apt-transport-https -y 

Docker CEのインストールにはca-certificatesが必要です。ca-certificatesをインストールするには、コマンドを実行します。

# sudo apt-get install ca-certificates -y 

Docker CEのインストールにはcurlが必要です。curlをインストールするには、コマンドを実行します。

# sudo apt-get install curl -y 

Docker CEのインストール

Dockerコミュニティ版をインストールするには、以下の手順に従います。

ステップ1:

以下のコマンドを実行して、Docker用のGPGキーを追加します。

# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add –

ステップ2:

以下のコマンドを実行して、GPGキーのフィンガープリントを確認します。

# sudo apt-key fingerprint 0EBFCD88

ステップ3:

以下のコマンドを実行してDockerリポジトリを追加します。

# sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable”

ステップ4:

以下のコマンドを実行してシステムをアップデートし、追加されたリポジトリをロードします。

# sudo apt update

ステップ5:

以下のコマンドを実行してDockerをインストールします。

# sudo apt install docker-ce

ステップ6:

以下のコマンドを実行して、ユーザ名をdockerグループに追加します。

# sudo adduser aareez docker 

ステップ7:

現在のシェルセッションを閉じて、新しいセッションを開始します。そうしないと、dockerを実行することができず、パーミッションエラーが表示される可能性があります。

ステップ8:

以下のコマンドを実行して、dockerが正しく実行されているかどうかを確認します。

# docker run hello-world

NextCloudのインストール

NextCloudとTalkをインストールするには、以下の手順に従ってください。

ステップ1:

次のコマンドを実行して、NextCloudをDockerにダウンロードしてインストールします。

# docker run -d -p 8080:80 nextcloud

Docker composeをインストール

アップグレードによるデータの一貫性を保ち、再起動時にすべてのコンテナを自動的に処理するために、Docker composeを使用することができます。データベースコンテナとパーシステントボリュームを分けて設定を起動するのが簡単です。Docker composeをダウンロードしてインストールするには、以下の手順に従ってください。

ステップ1:

以下のコマンドを実行して、最新版のdocker composeをダウンロードしてインストールします。

# sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose

ステップ2:

以下のコマンドでファイルのパーミッションを設定します。

# sudo chmod +x /usr/local/bin/docker-compose

ステップ3:

以下のコマンドで起動したコンテナの一覧を取得します。

# docker container ls —all

image.png

8080番ポートを使用しているコンテナを停止させます。そのためには、コンテナIDを取得し、以下の8baab990c424に置き換えてコマンドを実行します。

# docker stop 8baab990c424

ステップ4:

オプション1 - SSLなし

SSL証明書をインストールしたい場合は、以下の手順をスキップして、オプション2 - SSLを使用して、本項の手順5から進めます。

docker-compose.yamlファイルを作成し、設定用の以下のテキストを貼り付けて保存します。テキストを貼り付ける前に、データベース名、パスワード、ユーザーを忘れずに設定してください。

# sudo nano docker-compose.yaml
version: '2'

volumes:
  nextcloud:
  db:

services:
  db:
    image: mariadb
    restart: always
    volumes:
      - db:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=654321Ab
      - MYSQL_PASSWORD=654321Ab
      - MYSQL_DATABASE=ncdb
      - MYSQL_USER=aareez

  app:
    image: nextcloud
    ports:
      - 8080:80
    links:
      - db
    volumes:
      - nextcloud:/var/www/html
    restart: always

以下のコマンドを実行して、Docker Composeの設定を起動します。

# docker-compose up -d

オプション2 - SSLを使用した場合

ファイアウォールとポートの設定

ファイアウォールを有効にしている場合は、クラウドサーバーの Alibaba Cloud セキュリティグループで、ポート 80/tcp と 443/tcp の例外を追加するルールを定義する必要があります。ECSインスタンスを作成する際にこれらのポートを有効にすることができますが、これらのポートのブロックを解除し忘れた場合は、このガイドの手順に従うことができます: https://www.alibabacloud.com/help/doc-detail/25471.htm

リバースプロキシの設定

以下のコマンドで起動したコンテナの一覧を取得します。

# docker container ls --all

8080番ポートを使用しているコンテナを停止させます。そのためには、コンテナIDを取得し、以下の8baab990c424に置き換えてコマンドを実行してください。

# docker stop 8baab990c424

このステップでは、NextCloud Talkにアクセスするためのリバースプロキシを設定して、アドレスの末尾にポートを使わずにドメイン名でアクセスできるようにします。そのためには、docker-compose.ymlファイルを以下のテキストで更新する必要があります。

# sudo nano docker-compose.yml

次に、開いたファイルに以下のテキストを追加して保存します。

version: '3'

services:
  db:
    image: mariadb
    command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
    restart: always
    volumes:
      - db:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=654321Ab
      - MYSQL_PASSWORD=654321Ab
      - MYSQL_DATABASE=ncdb
      - MYSQL_USER=aareez

  app:
    image: nextcloud:apache
    restart: always
    volumes:
      - nextcloud:/var/www/html
    environment:
      - VIRTUAL_HOST=softpedia.xyz
      - LETSENCRYPT_HOST=softpedia.xyz
      - LETSENCRYPT_EMAIL=arslan@gmail.com
      - MYSQL_HOST=db
      - MYSQL_PASSWORD=654321Ab
      - MYSQL_DATABASE=ncdb
      - MYSQL_USER=aareez
    depends_on:
      - db
    networks:
      - proxy-tier
      - default

  proxy:
    build: ./proxy
    restart: always
    ports:
      - 80:80
      - 443:443
    labels:
      com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy: "true"
    volumes:
      - certs:/etc/nginx/certs:ro
      - vhost.d:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - /var/run/docker.sock:/tmp/docker.sock:ro
    networks:
      - proxy-tier

  letsencrypt-companion:
    image: jrcs/letsencrypt-nginx-proxy-companion
    restart: always
    volumes:
      - certs:/etc/nginx/certs
      - vhost.d:/etc/nginx/vhost.d
      - html:/usr/share/nginx/html
      - /var/run/docker.sock:/var/run/docker.sock:ro
    networks:
      - proxy-tier
    depends_on:
      - proxy

volumes:
  db:
  nextcloud:
  certs:
  vhost.d:
  html:

networks:
  proxy-tier:

ここで、proxy という名前のディレクトリを作成します。

# sudo mkdir proxy

作成されたプロキシディレクトリに移動します。

# cd proxy

ここでDockerfileというファイルを作成し、開いたファイルに以下のテキストを貼り付けて保存します。

# sudo nano Dockerfile
FROM jwilder/nginx-proxy:alpine

COPY uploadsize.conf /etc/nginx/conf.d/uploadsize.conf

今すぐuploadsize.confを作成し、開いたファイルに以下のテキストを貼り付けて保存します。

# sudo nano uploadsize.conf
client_max_body_size 10G;

ホームディレクトリに移動します。

# cd ~

これでDocker composeの設定を起動します。

# sudo docker-compose up -d

ステップ5:

ブラウザを開き、http://your_domain.tld:8080 または http://ecs_ip_address:8080 に移動します。ページの読み込み中にエラーが表示された場合は、ファイアウォールの設定セクションに移動し、ポート8080を有効にします。リンクにアクセスすると、以下のような画面が表示されます。

image.png

ステップ6:

以下のフォームに必要事項を入力して、管理者アカウントを作成します。

image.png

ステップ7:

ストレージとデータベースのドロップダウンをクリックして、データベース情報を入力します。ホスト値を使用してください:db

image.png

データを入力したら、「セットアップを完了する」をクリックします。これでNextCloudのダッシュボードにリダイレクトされます。

image.png

Talkをインストール

Talkは、テキストとビデオチャットを行うために提供しています。それはあなたが通話をするのに役立ちます。そのためには、以下の手順に従ってください。

ステップ 1:

右上のプロフィール写真のアイコンに移動すると、ドロップダウンメニューが開きます。下図のように+Appsをクリックします。

image.png

ステップ2:

ソーシャル&コミュニケーションセクションに移動します。アプリのリストが表示されます。下図のように開いたリストからトークを選択します。ダウンロードして有効にするオプションをクリックして、インストールを待ちます。

image.png

正常にインストールされた後、上部のメニューバーに新しいアイコンが表示されますので、それをクリックしてください。

image.png

以下のような画面が表示されます。左側に追加されたユーザーの一覧が表示されます。電話をかけたり、チャットをしたりすることができます。

image.png

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

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

OS自作環境をMacに作成する

Macのバイナリー形式よりもELFのほうがなにかと楽なのでクロスコンパイル環境を構築します。

Dockerでクロスコンパイル環境をインストール

以下Dockerファイル
```Dockerfile
FROM ubuntu:latest
MAINTAINER username
WORKDIR /home/projects

RUN apt-get update && apt-get install -y \
vim \
gcc \
g++ \
binutils \
build-essential

ビルド

docker run --rm -v $PWD:/home/projects 9665b0eb66db /bin/bash -c "cd /home/projects; make clean & make" |
```

QEmuをインストール

コンパイルしたファイルを実行するための仮想環境を構築します。

brew install qemu

これで環境準備が出来ました。

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

Bitbucketからコンテナサービスにアプリをデプロイする方法

今回のチュートリアルでは、BitbucketからAlibaba Cloudコンテナサービスにアプリケーションをデプロイし、Let's Encrypt SSL/TLS 2019でセキュリティを確保します。

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

Docker

Dockerは、コンテナを使ってアプリケーションを作成、デプロイ、実行するために設計されたオープンソース・ソフトウェアです。コンテナを利用することで、開発者はアプリケーションに必要なライブラリやその他の依存関係などをすべてパッケージ化し、1つのパッケージとして出荷することができます。そうすることで、コンテナのおかげで、開発者は、コードを書いたりテストしたりするために使用するマシンとは異なるカスタマイズされた設定があっても、他の Linux マシン上でアプリケーションを実行することができるので、安心してください。

コンテナは仮想マシンに少し似ています。しかし、仮想マシンとは異なり、仮想オペレーティングシステム全体を作成するのではなく、Dockerではアプリケーションは実行中のシステムと同じLinuxカーネルを使用することができ、アプリケーションはホストコンピュータ上で実行されていないものと一緒に出荷される必要があるだけです。これにより、パフォーマンスが大幅に向上し、アプリケーションのサイズを小さくすることができます。

このチュートリアルでは、Dockerを使ってアプリケーションをコンテナ化し、Alibaba Cloud Container Service上でデプロイして実行できるようにします。

Bitbucket

Bitbucketは、プロのチーム向けに設計されたGitバージョン管理リポジトリ管理ソリューションです。gitリポジトリの管理、ソースコードのコラボレーション、開発フローのガイドなどを一元的に行うことができます。最大5人の協力者と無制限に無料のプライベートリポジトリを作成することができます。これは、プロプライエタリなコードをホストするのに最適な場所になります。

主な機能は以下の通りです。

1、ソースコードへのアクセスを制限するアクセスコントロール。
2、プロジェクトやチームのワークフローを強制するワークフローコントロール。
3、コードレビューでの共同作業のためのインラインコメント付きのプルリクエスト。
4、開発の完全なトレーサビリティのための Jira 統合
5、マーケットプレイスから利用可能な機能がない場合、ワークフローに合わせたカスタム機能を構築するためのFull Rest API
このチュートリアルでは、Bitbucketを使用してアプリケーションのコードのリポジトリをホストし、CI/CDパイプラインを作成してAlibaba Cloud Container Serviceにアプリケーションをデプロイします。

Alibaba Cloud Container Registry

Alibaba Cloud Container Registry (ACR)は、コンテナ化されたイメージのライフサイクル管理を提供する安全なイメージホスティングプラットフォームです。ACRを使用すると、保存されたイメージを完全にコントロールすることができます。ACRには、GitHubやBitbucketなどとの統合を含む多くの機能があります。また、ソースコードからアプリケーションへのコンパイルやテスト後に自動的に新しいイメージを構築することもできます。画像レジストリの作成やメンテナンスを簡素化し、複数のリージョンでの画像管理をサポートします。Container Serviceなどの他のクラウドサービスと組み合わせることで、Container RegistryはクラウドでDockerを利用するための最適なソリューションを提供します。

このチュートリアルでは、DockerイメージのホスティングにACRを使用して、後からAlibaba Cloud Container Service上にアプリケーションをデプロイするために使用します。

Alibaba Cloud Container Service

Alibaba Cloud Container Service(ACS)は、DockerとKubernetesを使用してコンテナ化されたアプリケーションのライフサイクルを管理できる、高性能で拡張性の高いコンテナアプリケーション管理サービスです。

Container Serviceは、さまざまなアプリケーションの公開方法や継続的なデリバリー機能を提供し、マイクロサービスアーキテクチャをサポートしています。

Container Serviceはコンテナ管理クラスタの構築を簡素化し、アリババクラウドの仮想化、ストレージ、ネットワーク、セキュリティ機能を統合して、クラウド上に最適なコンテナ実行環境を構築します。

このチュートリアルでは、Alibaba Cloud Container Serviceを使用して、マイクロサービスをホストしてデプロイする方法を説明します。

Node.js

Node.jsは非同期イベント駆動型のJavaScriptランタイム環境です。これはスケーラブルなネットワークアプリケーションを構築するために設計されています。Node ランタイム環境には、JavaScript で書かれたプログラムをスタンドアロンアプリケーションとしてマシン上で実行するために必要なものがすべて含まれています。Node.js は V8 JavaScript ランタイムエンジン上で動作します。このエンジンはJavaScriptのコードを受け取り、より高速なマシンコードに変換します。マシンコードとは、コンピュータが最初に解釈しなくても実行できる低レベルのコードのことです。

このチュートリアルでは、Node.js を使ってシンプルな "Hello World" アプリケーションを作成し、ACS をデプロイしてみます。

SSL/TLSを暗号化してみよう

Let's Encryptは世界的な認証局(CA)です。彼らは、世界中の人々や組織が SSL/TLS 証明書を取得、更新、管理できるようにしています。これらの証明書は、ウェブサイトが安全な HTTPS 接続を可能にするために使用することができます。Let's Encrypt は、ドメイン検証(DV)証明書のみを提供しています。これらの証明書に手数料はかかりません。Let's Encrypt は、HTTPS の普及を促進することで、より安全でプライバシーを尊重した Web を構築することを使命とする非営利団体である。彼らのサービスは無料で簡単に利用できるので、どんなウェブサイトでも HTTPS を導入することができます。

このチュートリアルでは、Let's Encrypt SSL/TLSを使用してアプリケーションのセキュリティを確保します。

前提条件

まず最初に、アプリケーションのコードのプライベートリポジトリをBitbucket上に作成します。アカウントを持っていない場合は、アカウントにサインアップすることができます。

次に、Alibaba Cloud Servicesを使ってDockerイメージを作成し、コンテナ化されたアプリケーションをデプロイします。そのため、Alibaba Cloudのアカウントも設定しておく必要があります。アカウントを持っていない場合は、このリンクから無料のアカウントにサインアップすることができます。

パートⅠ:Bitbucket Gitリポジトリにアプリを追加する

このセクションでは、Bitbucket Gitリポジトリを作成し、そこにアプリケーションとDockerの設定を追加していきます。

ステップ1: Bitbucketリポジトリの作成

まず、Bitbucketアカウントにログインし、左メニューバーにある「+」ボタンをクリックし、オプションから「リポジトリ」を選択し、「新しいリポジトリの作成」フォームで、リポジトリの名前を入力します。そして、「リポジトリの作成」ボタンを押します。

image.png

ステップ2: アプリケーションファイルとDockerファイルをリポジトリに追加する

リポジトリの作成に成功したので、アプリケーションとDockerのファイルをリポジトリに追加していきます。

まずはローカルディレクトリに git を初期化します。まず、ローカルマシン上に空のディレクトリを作成し、"sample-app-for-alibaba-cloud "と名付け、"Git Bash "またはお好みのCLIで開きます。そして、その中でgit initcommandを実行します。

では、そのディレクトリにファイルを追加していきます。まず、以下のような内容のアプリケーションファイル "app.js "を追加します。

const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});
server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

これで、ポート3000のNode.jsが組み込まれたサーバ上で動作するシンプルな「Hello World」アプリが作成されます。

ここでは、Dockerの設定ファイル「Dockerfile」を追加し、以下の内容で作成します。

# Use Node version 10.15.1
FROM node:10.15.1
# Create a directory where our app will be placed
RUN mkdir -p /usr/src/app
# Change directory so that our commands run inside this new directory
WORKDIR /usr/src/app
# Get all the code needed to run the app
COPY . /usr/src/app
# Expose the port the app runs in
EXPOSE 3000
# Serve the app
CMD node app.js

ファイル内のコメントは、各行が何をするのかを説明する必要があります。このファイルで設定した内容をもとに、アプリケーションのコンテナイメージをどのように作成するかを決定します。

これで、これらのファイルを先ほど作成した Bitbucket リポジトリにプッシュする準備が整いました。

git add .
git commit -m "app.js and dockerfile added"
git remote add origin https://your-username@bitbucket.org/your-username/the-repo-name.git
git push -u origin master

パートII: BitbucketとACRの統合

最初に行う必要があるのは、Alibaba Cloud Container Registryを有効化することです。これは、Alibaba Cloud Consoleの「Elastic Computing」セクションの下にあります。

Container Registry Consoleに移動し、サービスを構成してデプロイすることができます。その際に、dockerクライアントのパスワードの入力を求められることがあるので、「dockerにログインする際には、先ほど設定したユーザー名とパスワードをAlibaba Cloudアカウントで使用する」と覚えておきましょう。

では、新しい ACR Namespace を作成します。 通常はコンテナを使ってマイクロサービスを作成します。 今回のアプリケーションでは単一のサービスのみを使用していますが、現実世界では通常そうはいきません。 そこで、ACR Namespacesの出番です。名前空間はレポジトリーのコレクションであり、リポジトリはイメージのコレクションです。 各アプリケーションに1つの名前空間を作成し、各サービスイメージに1つのリポジトリを作成することをお勧めします。

新しいネームスペースを作成するには、ACRコンソールのNamespacesタブに移動し、右上の "Create Namespace "ボタンをクリックします。 その後、名前空間の名前を入力し、"Confirm "ボタンをクリックします。

image.png

ここで、BitbucketアカウントをACRにバインドします。これを行うには、メインACRコンソールの "Code Source "タブに移動し、そこからBitbucketの横にある "Bind Account "ボタンをクリックしてください。

image.png

これでBitbucketに移動し、Alibaba Cloudへのアクセスを許可するように要求されます。そこで「アクセスを許可する」ボタンをクリックして次に進みます。

image.png

これで、ACR リポジトリを作成する準備ができました。リポジトリの詳細を入力するフォームが表示されますので、地域、名前空間、リポジトリ名、概要などを入力してください。

image.png

必要事項を記入した後、「次へ」ボタンをクリックしてください。次のページでは、「コードソース」オプションを選択するフォームが表示されます。このページでは、Bitbucket リポジトリを ACR リポジトリと統合します。Code Source "タブから "Bitbucket "を選択し、先ほど作成したBitbucket Repositoryをクリックします。

継続的インテグレーションの設定を支援するために、「イメージを自動的にビルドする」にチェックを入れてください。これを選択すると、コードを送信した後にイメージが自動的にビルドされ、手動でビルドを開始する必要はありません。最後に「リポジトリの作成」ボタンをクリックして、ACRリポジトリを作成し、Bitbucketリポジトリとの統合を行います。

image.png

パート III: アプリケーションのデプロイ

まず、VPC を作成する必要があります。そのためには、ネットワークの下の仮想プライベートクラウドに移動するだけです。VPC コンソールに移動し、"Create VPC" ボタンをクリックして VPC と VSwitch を作成します。ボタンをクリックすると、新しいVPCのオプションを選択するための小さなフォームが表示されますが、ここではデフォルトの設定を使用して名前を入力し、「OK」ボタンをクリックして続行します。

image.png

Alibaba Cloud Cloud Serviceを使い始めるには、まず、コンテナサービスのダッシュボードに移動します。このダッシュボードは、Alibaba Cloud ConsoleのElastic Computingセクションの下にあります。

最初に試してみると、「コンテナサービスはデフォルトのロールを作成する必要があります」という警告が表示されることがあります。これは、クラスタをリクエストすると、Alibaba Cloudがクラスタの実行に必要なリソースのプロビジョニングを行うためです。これには、ロードバランサー、仮想マシン、ルーターなどが含まれます。基本的には、自分のDockerクラスタを動かすために必要なものはすべて含まれています。そして、ロードバランサは動作する前にRAM(Resource Access Management)サービスを設定する必要があります...。これに対処するには、"Go to RAM console "ボタンをクリックし、リダイレクトされたら "Confirm Authorization Policy "ボタンをクリックします。

Container Service Overviewのページが表示されますので、左上の "Container Serv-Swarm "を選択し、"Create Cluster "ボタンをクリックします。

image.png

これでクラスタ作成ウィザードに移動します。名前、地域、ゾーン、VPCなど、クラスタを構成するために必要なすべてのオプションが表示されます。

image.png

大部分はデフォルト値を使用しますが、このデモの目的のために、"Instance Configuration "の "Instance Type "を "1 Core(s) 1 G ( ecs.n1.tiny ) "に変更します。また、このクラスタのために作成されるECSインスタンスのログインを設定する必要があります。これを設定した後、"Create "ボタンをクリックして続行します。その後、作成されたクラスタのすべての詳細を示すダイアログが表示されますので、すべてが正しいことを確認し、"OK "ボタンをクリックして続行します。

image.png

ここで、Bitbucket上にソースコード用のTag(release)を作成します。これを行うには、まず、先ほど作成したBitbucketリポジトリのコミットページに移動し、そこにプッシュした最新のコミットを選択します。そのページの右側に "タグ "オプションがあり、その横に "+"ボタンがありますので、それをクリックすると、新しいタグを作成するためのダイアログが開きます。

image.png

次に、ACR コンソールのリポジトリに戻り、先ほど作成した ACR リポジトリの横にある「管理」ボタンをクリックします。

image.png

リポジトリの詳細ページに移動し、リポジトリの名前、地域、タイプ、コードリポジトリリンク、インターネットアドレス、VPCアドレスなどの詳細が表示されます。そこから「ビルド」タブに移動し、「ビルドログ」の下に先ほど作成したタグのビルドが表示されます。ビルドのステータスが "Successful "になったら、右上の "Deploy Application "ボタンをクリックします。Container Cluster "オプションで "Swarm "を選択し、"Deploy "ボタンをクリックします。

image.png

これにより、ACSアプリケーション作成ウィザードに移動します。そこでは、「基本情報」タブで、名前、バージョン、クラスタ、更新、説明などのオプションが用意されています。名前を入力し、先ほど作成したクラスタを選択し、「Pull Docker Image」にチェックを入れて「Next」ボタンをクリックして次に進みます。

image.png

これで作成ウィザードの "Configuration "タブに移動します。ここではDockerコンテナの「Image Name」と「Image Version」を選択し、「Port Mapping」の「host Port」に「3000」を使用します。次に、「Web routing」の下にある「Port」と「Domain」を追加します。このページには他にも多くの設定オプションがありますが、ここではデフォルト値を使用します。ここで「作成」ボタンをクリックして、いよいよアプリケーションを作成します。

image.png

完了ページで "View Application List "リンクをクリックしてアプリケーションの一覧ページに進みます。次に「ルート」タブをクリックして、アプリケーションのアクセスエンドポイントを取得します。

image.png

これで、コンテナ化されたアプリケーションのデプロイに成功しました。さて、最後のパートに入りましょう。

パートIV: SSL/TLSを暗号化してアプリケーションを保護しよう

これを始めるには、まず、John HanleyによるAlibaba Cloud上でのLet's Encrypt ACMEの構成に関するこのガイドに従うべきである。さて、すべての設定を行い、証明書ファイルを作成したら、前述の手順に進みます。

サーバーのロードバランサー層ではHTTPSに対応しているので、HTTPSに対応しているかどうかを確認します。HTTPS をサポートするには、Server Load Balancer 証明書を作成する必要があります。これを行うには、ネットワーキングの下のサーバーロードバランサーコンソールに移動し、左パネルの「Certificates」リンクをクリックして「Certificates」ページに進みます。証明書の作成」ボタンをクリックし、「サードパーティ証明書のアップロード」オプションを選択して「次へ」ボタンをクリックします。

image.png

これで「Upload Third-Party Certificate」に移行し、必要事項を記入して「次へ」ボタンをクリックします。

image.png

証明書が正常に作成されたら、サーバーロードバランサーのページに移動し、クラスタ作成時に割り当てられたサーバーロードバランサーのインスタンスを探してクリックします。インスタンスに移動したら、「リスナー」タブの下にある「リスナーの追加」ボタンをクリックします。

image.png

リスナーを追加するためのウィザードが開きます。そこから、このガイドに従って HTTP を HTTPS に変更してウィザードを記入します。これで、Let's Encrypt SSL/TLSで保護されたコンテナ化アプリケーションが完成しました。

出典:コンテナ化されたアプリケーションのデプロイ方法の基本的なガイド BitbucketからAlibaba Cloud Container Serviceにアプリケーションをデプロイし、Let's Encrypt SSL/TLSでセキュリティを確保する方法の基本ガイド2019

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

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

エラー「ERROR: The Compose file './docker-compose.yml' is invalid because:」の対処法

ERROR: The Compose file './docker-compose.yml' is invalid because:
services.php.volumes contains an invalid type, it should be an array

docker-compose upした時に上記のようなエラーが出た場合の対処法です。

原因はYaml文法エラー

エラー内容のservices.php.volumesの部分の文法が不正ということです。

Before : 不正な文法

(不正文法)docker-compose.yml
version: '3'
services:
  nginx:
    image: nginx:latest
    ports:
      - 8080:80
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
      - ./wwww/html:/var/www/html
    depends_on:
      - php
  php:
    build: ./php
    volumes:
      -./www/html:/var/www/html

After : 正しい文法

(正しい文法)docker-compose.yml
version: '3'
services:
  nginx:
    image: nginx:latest
    ports:
      - 8080:80
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
      - ./wwww/html:/var/www/html
    depends_on:
      - php
  php:
    build: ./php
    volumes:
      - ./www/html:/var/www/html

具体的には以下の部分です。

Before : 不正な文法

-./www/html:/var/www/html

After : 正しい文法

- ./www/html:/var/www/html

Yamlの文法は-(ハイフン)の後ろには必ず半角スペースが必要です。
うっかり見落としていました。

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

Firefoxでlocal(localhost)のサブドメインに接続できない問題

Firefoxでlocalのサブドメインに接続できない問題

問題

Docker等でサーバーを立ち上げ、
以下のURLにFirefoxでアクセスしたいとき
http://subdomain.localhost/
エラーが表示されてしまいます。

解決方法

  1. URL欄にabout:configを入力し設定画面を表示
  2. 検索欄にnetwork.dns.localDomainsを入力し検索
  3. valueの欄をダブルクリックし、入力できるようにする
  4. subdomain.localhostを登録する。(複数登録したい場合は、カンマ区切りで)

参考にしたリンク

https://stackoverflow.com/questions/33251155/firefox-cannot-connect-to-a-local-servers-subdomain

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

VSCodeとRemote-Containersとリモートdocker-daemonで最強の環境を手に入れる

はじめに

開発環境構築は開発において最初の関門であり、面倒だし複雑な作業です。

  • 従来の環境と衝突して全てが壊れる
  • チームのメンバーと微妙に環境が異なってトラブルが発生する
  • 環境構築手順が複雑でミスしやすい
  • 何かが起きた時に原因究明が難しい

基本編では環境開発の面倒さを解決し、応用編ではさらにセキュリティと開発体験を両立した新しい開発を提案します。
この方法はほとんどの言語に適用可能ですが、今回は開発環境構築が面倒な言語の一つであるpythonを例に説明します。

目次

  1. 基本編: Remote-Containersを使って開発環境レス開発をする
  2. 応用編: Remote-Containers + Cloud + シンクライアントPCで最強の環境を手に入れる
  3. 実践編: 実際の開発チームで活用するパターン(後日追記予定)

応用編からが本命です

基本編: Remote-Containersを使って開発環境レス開発をする

VSCodeRemote-ContainersというExtensionをご存知ですか?
知っていたらこの基本編を飛ばし応用編へどうぞ!

公式ページのイメージ図です
architecture-containers.png

簡単にRemote-Containersを説明すると、開発環境をdocker containerで構築し、その中でコードを実行するが、コードの編集やデバッグは手元のVSCodeで行えるという神Extensionです。

開発環境をcontainerに閉じ込めるので

  • PCの開発環境を汚さない
  • 環境が全てコード化されていて、git管理しやすい
  • 開発メンバー間で環境が必ず同じになる

などのメリットがあります。デメリットはほぼありません。
宗教上の理由でVSCodeを使えない人以外は使った方がいいレベルのExtensionです。
こちらに関しては既に様々な記事が書かれているので、導入方法などはそちらを参考にしてください。

Remote-Containersの参考リンク

基本編まとめ

「巨人の肩の上に立つ」ということで基本編の詳しい説明はこの記事ではしませんでしたが、是非参考リンクを見て導入してみてください。
もう開発環境構築で悩むことはなくなります。
(pythonの環境構築ツール戦争にも終止符が打たれるといいなぁ)

応用編: Remote-Containers + Cloud + シンクライアントPCで最強の環境を手に入れる

こちらがこの記事の本命です!
Remote-Containersの基本は抑えた前提で話を進めます。

概要説明

Remote-Containersはdocker上で開発を行うツールですので、実はローカルPCのdocker-daemonを使う必要はありません。
つまり、以下のような構成が可能です。

design.png

ここで重要なのは

  • 秘匿性が高く、持ち出したくない「ソースコード」
  • マシンパワーが必要な「ビルド & デバッグ」

がリモートマシン上。というところと

  • キー入力などレスポンスが気になる「IDE」
  • 流出しても大した影響のない「Remote-Contaienrs用設定ファイル」

がローカルマシン上。というところ。
つまり、ローカルマシンは弱々スペックなシンクライアントPCで、VSCodeとその設定だけを保持。ソースコードとデバッグは強いリモートサーバ上という構成が可能。
これは、開発体験とセキュリティを両立しており、新しい開発スタイルになりうるのではと思っています。

実際にやってみる on GCP

今回は手元のPCとGCP上のインスタンスを用いて実際に構築してみる。
AWSでも、Azureでもなんでも大丈夫です。GCP以外を使いたい人は適宜読み替えてください。

前提

  • GCPが使える状態になっている
  • gcloudコマンドが使える状態になっている

GCP上にインスタンスを構築し、sshの設定を保存する

GCPにはコンテナを立てることに特化したVMイメージが用意されているので、今回はそちらを使います。
zoneはご自由に設定してください。

gcloud compute instances create [instance_name] \
--image-family cos-stable \
--image-project cos-cloud \
--machine-type n1-standard-1

インスタンスが立ち上がったら、sshしてみます。

gcloud compute ssh [instance_name]

無事にsshができたらsshの設定を手元のPCに書き出します。

gcloud compute config-ssh

これで、sshの鍵が手元のPCに保存され、ssh [instance_name].[zone].[project_name]でsshできるようになります。試してみてください。

VM上にプロジェクトを作成する

VMにsshしてください。既にgitコマンドが入っていると思うので、任意のプロジェクトをgitからcloneしてください。

特に思いつかない場合はapp.pyrequirements.txtを作成してください。
アクセス権には注意してください。containerの中から触るのでdockerグループにアクセス権が必要です。
面倒であれば今回はchmod 777 -R [プロジェクトディレクトリパス]でとりあえずアクセス権ガバガバにしておいてください。

手元のPCの上にRemote-Conteinrs用の設定ファイルを作成する

設定ファイル用のディレクトリを作成して、そこにRemote-Container用の設定ファイルを配置します。pythonプロジェクトを例にして説明します。
まずは設定ファイルが入っているmicrosoftのサンプルプロジェクトをcloneします。

git clone https://github.com/microsoft/vscode-remote-try-python.git

python用のファイルがいろいろ入っているので、

  • .devcontainer
  • .vscode

以外は全て削除してください。
次に、Remote-ContaienrsプラグインでGCP上のVMのdocker-daemonを使う設定を追加します。
.vscodeの中にsetting.jsonを作成し、以下を書き込みます。

{
    "docker.host": "ssh://[container_name].[zone].[project_name]"
}

次にプロジェクトのマウント対象ディレクトリを変更します。
.devcontainer/.devcontainer.jsonに二つのkey-valueを追記します。

"workspaceMount": "source=[GCP上のprojectのフルパス],target=/workspace,type=bind,consistency=delegated",
"workspaceFolder": "/workspace"

この設定で、GCP上でcontainerを立てた時に、先ほど作成したプロジェクトをマウントするようにします。

Remote-Containersで開発する

vscodeのRemote-ContainersプラグインのメニューからReopen in Containerを選択すると、GCPのVM上のdocker-daemonに接続し、containerを立て、そこでプロジェクトを開きvscodeを接続します。

あとは、自由に開発できます!

まとめ

今回は基本編と応用編に分けて説明しました。
基本編やRemote-Containerの詳しい説明は省いてしまいましたが、Remote-Containerを普通に使用するだけでも、開発環境構築が不要になったり、メンバー間で環境が統一できたりとかなりのメリットがあります。
さらに、応用編で紹介したリモートのdocker-daemonを使用する方法を使うことで、手元のPCにコードを置かない、計算リソースを強力なPCに寄せる運用が可能になります。セキュリティと開発体験を両立した開発手法だと考えています。

ぜひ試してみてください。

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

docker rails db:migrateにてエラー(StandardError: An error has occurred, all later migrations canceled:)

Qiita初投稿となります。よろしくお願いします。

環境

  • image: mysql:5.7
  • FROM ruby:2.6.3
  • Rails 5.2.4.3

エラー

docker環境で構築したrailsにて、docker-compose exec web rails db:migrateとしたところ、以下エラー

rails aborted!
StandardError: An error has occurred, all later migrations canceled:

Mysql2::Error: Invalid use of NULL value: ALTER TABLE `tasks` CHANGE `name` `name` varchar(255) NOT NULL
....以下省略

原因

完全な特定には至らなかったが、以前行ったマイグレーションの処理がうまくいっていない可能性がある。テーブル作成周りでエラーが出ていた。
エラーのMysqlに関しては修正しているはず・・・。

解決方法

データベースのリセットを行う。

$ docker-compose exec web rails db:migrate:reset

再度マイグレーション

$ docker-compose exec web rails db:migrate

これで修復できました。確認の為、コンソールから正しくDB周りが動いてるか見るといいと思います。

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

AnsibleをDockerコンテナで実行

概要

コントロールノード(ホストOS)からAnsibleを実行し、ターゲットノードのDockerコンテナの環境を構築する。

背景

Dockerコンテナの環境をAnsibleで構築する際に、筆者はこれまでDockerコンテナ内にAnsibleをインストールして試したことしかなかった。
しかしDockerコンテナにAnsibleをインストールせずとも、ホストOSからAnsibleを実行してDockerコンテナの環境を作れることがわかったため、本記事で共有する。

本記事のポイント

  • DockerコンテナにAnsibleはインストール不要。(ホストOSにはインストール必要)
  • 通常Ansibleを実行するのに、デフォルトではコントロールノードからターゲットノードへsshでログイン可能な状態にする必要があるが、予め接続方法をDocker向けにカスタマイズするためssh設定は不要。また、Ansibleを実行するためにDockerコンテナの特定ポートをホストOSに向けて開ける必要も無し。

手順

(1) 元となるDockerコンテナの準備

  • CentOS7のコンテナを使う例
  • 暫定で使うので、コンテナを停止したらコンテナが消える--rmオプションをつけている
  • 対象コンテナを既に立ち上げている場合はこの手順はスキップしてOK
    • 以後に出てくるcentos7も、各自のコンテナ名に置き換えて試していただく必要あり
$ docker run -dit --name centos7 --rm centos:7 /bin/bash

(2) ターゲットノードのホスト情報を記述した設定ファイルの準備

  • カレントディレクトリ(作業するディレクトリ)に、Dockerコンテナのホスト情報を記載した設定ファイルを用意
hosts
[servers]
centos7

[all:vars]
ansible_connection=docker
  • 要点
    • [servers]セクションにターゲットノードのホスト名(つまりDockerコンテナ名)を記載。
    • 変数を定義するセクション[all:vars]に、ターゲットノードがDockerコンテナであることを表すansible_connection=dockerを記載
  • 余談
    • [servers]セクションに複数のホストを指定することも可能。また、セクションはホストを例えばDB向け、AP向けなどのようにグループ化するために利用するもので、どのような名前にするかは任意。今回の例では、コンテナcentos7への接続を確認するだけなので、[servers]というセクションの記載がそもそも無くても(centos7のみ記載していれば)動作する模様。
    • ansible_connectionに関して。ssh無しで自分自身のマシンにAnsibleを適用したい場合は、ansible_connection=localにするといいみたい。

(3) 動作確認

  • 以下コマンドで、Dockerコンテナ内でpingできることを確認
$ ansible centos7 -i hosts -m ping
centos7 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
  • ちなみにカレントディレクトリにansible.cfgを用意して、ターゲットホスト(およびそれに付随する設定)を定義したファイルhostsを参照する旨を記載していれば、上記コマンドで-iオプションは不要。
ansible.cfg
[defaults]
inventory=./hosts

注意点

本記事で扱う内容に限った話ではないが、Ansibleの裏ではpythonが動いているため、対象コンテナ内にpythonが入っていなければ動作しない。
また仮にpythonが入っていても、pythonの実行ファイルパスがAnsibleのデフォルトである/usr/bin/pythonでなければエラーになってしまう。その場合は、先に示したホストの設定ファイルhostsの変数セクションに、下記のようにansible_python_interpreterを追記してあげればOK。

hosts
(ホスト名の定義など)

[all:vars]
ansible_connection=docker
# 以下、追記した例
ansible_python_interpreter=/usr/bin/python3
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerでwheneverを扱う時No such file or directory - crontabが出る

簡単に定時処理が書ける便利なgem「whenever」

dockerでアプリ作成時、wheneverを使った処理をしようとしたが、つまづいてしまったので忘備録として記述しておきます。

環境

Ruby 2.5.1
Rails 5.2.4.3

やりたいこと

今回はpostというモデルを用意し、wheneverを使って1分事にpostを作成してみる。
dockerの環境構築は終わっているものとしてスタート。

modelとcontrollerを作成

docker上で

root@6181bdf78fa7:/myapp# bundle exec rails g model post name:string 
root@6181bdf78fa7:/myapp# bundle exec db:migrate
root@6181bdf78fa7:/myapp# bundle exec rails g controller posts

wheneverの設定

まずはgemをインストール

Gemfile
gem 'whenever', require: false

buildし直してgemをインストールしたらコマンドを実行してファイルを作成

root@6181bdf78fa7:/myapp# bundle exec wheneverize .
[add] writing `./config/schedule.rb'
[done] wheneverized!

作成されたschedule.rbに処理をかいていきます。

schedule.rb
require File.expand_path(File.dirname(__FILE__) + "/environment")
set :environment, :development
set :output, 'log/cron.log'
ENV.each { |k, v| env(k, v) }

every 1.minutes do
  runner "Post.create"
end

ここまできたら、cronに設定を反映させる

root@6181bdf78fa7:/myapp# bundle exec whenever --update-crontab
bundler: failed to load command: whenever (/usr/local/bundle/bin/whenever)
Errno::ENOENT: No such file or directory - crontab
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:77:in `popen'
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:77:in `write_crontab'
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:38:in `run'
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:6:in `execute'
  /usr/local/bundle/gems/whenever-1.0.0/bin/whenever:44:in `<top (required)>'
  /usr/local/bundle/bin/whenever:23:in `load'
  /usr/local/bundle/bin/whenever:23:in `<top (required)>'

エラーが出ましたね。
cron初心者の自分はここでつまづいてしまいました。

cronをインストール

どうやらdocker環境にcronをインストールしないといけないので、インストールに必要な処理をdockerfileに記述。
今回はこんな感じで1行追記しました。

FROM ruby:2.5.1
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN apt-get install -y cron  #この行を追記
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp
root@6710f08a3504:/myapp# bundle exec whenever --update-crontab
[write] crontab file updated

無事updateされてcronに反映されました。
これで自動処理が始まってると思い、しばらく待ってみます…

…どうやら動いてないですね。
wheneverが作動していればclog/cron.logが作成されるはずなので。

cronを起動させる

cronが動いていないので状態を確認します。

root@827fe138767f:/myapp# service cron status
[FAIL] cron is not running ... failed!

やはり動いていませんでした。
起動しましょう。

root@827fe138767f:/myapp# service cron start 
[ ok ] Starting periodic command scheduler: cron.

1分後…

cron.log
Running via Spring preloader in process 122

ついにcron.logが生成されlogが書かれました。
rails consoleで確認します。

root@827fe138767f:/myapp# bundle exec rails c
Running via Spring preloader in process 135
Loading development environment (Rails 5.2.4.3)
irb(main):001:0> Post.all.count
   (4.5ms)  SELECT COUNT(*) FROM "posts"
=> 1

データが生成されたのがわかりますね!

課題

しかしcronの起動は手動で毎回行うのは面倒なので、できればdockerfileに記述して自動で起動されるようにしたいところです。
今後その方法も追記していきたと思います。

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

Dockerでwheneverを扱う時No such file or directory - crontabとなる

簡単に定時処理が書ける便利なgem「whenever」

dockerでアプリ作成時、wheneverを使った処理をしようとしたが、つまづいてしまったので忘備録として記述しておきます。

環境

Ruby 2.5.1
Rails 5.2.4.3

やりたいこと

今回はpostというモデルを用意し、wheneverを使って1分ごとにpostを作成してみる。
dockerの環境構築は終わっているものとしてスタート。

modelとcontrollerを作成

docker上で

root@6181bdf78fa7:/myapp# bundle exec rails g model post name:string 
root@6181bdf78fa7:/myapp# bundle exec db:migrate
root@6181bdf78fa7:/myapp# bundle exec rails g controller posts

wheneverの設定

まずはgemをインストール

Gemfile
gem 'whenever', require: false

buildし直してgemをインストールしたらコマンドを実行してファイルを作成

root@6181bdf78fa7:/myapp# bundle exec wheneverize .
[add] writing `./config/schedule.rb'
[done] wheneverized!

作成されたschedule.rbに処理をかいていきます。

schedule.rb
require File.expand_path(File.dirname(__FILE__) + "/environment")
set :environment, :development
set :output, 'log/cron.log'
ENV.each { |k, v| env(k, v) }

every 1.minutes do
  runner "Post.create"
end

ここまできたら、cronに設定を反映させる

root@6181bdf78fa7:/myapp# bundle exec whenever --update-crontab
bundler: failed to load command: whenever (/usr/local/bundle/bin/whenever)
Errno::ENOENT: No such file or directory - crontab
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:77:in `popen'
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:77:in `write_crontab'
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:38:in `run'
  /usr/local/bundle/gems/whenever-1.0.0/lib/whenever/command_line.rb:6:in `execute'
  /usr/local/bundle/gems/whenever-1.0.0/bin/whenever:44:in `<top (required)>'
  /usr/local/bundle/bin/whenever:23:in `load'
  /usr/local/bundle/bin/whenever:23:in `<top (required)>'

エラーが出ましたね。
cron初心者の自分はここでつまづいてしまいました。

cronをインストール

どうやらdocker環境にcronをインストールしないといけないので、インストールに必要な処理をdockerfileに記述。
今回はこんな感じで1行追記しました。

FROM ruby:2.5.1
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs
RUN apt-get install -y cron  #この行を追記
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp
root@6710f08a3504:/myapp# bundle exec whenever --update-crontab
[write] crontab file updated

無事updateされてcronに反映されました。
これで自動処理が始まってると思い、しばらく待ってみます…

…どうやら動いてないですね。
wheneverが作動していればclog/cron.logが作成されるはずなので。

cronを起動させる

cronが動いていないので状態を確認します。

root@827fe138767f:/myapp# service cron status
[FAIL] cron is not running ... failed!

やはり動いていませんでした。
起動しましょう。

root@827fe138767f:/myapp# service cron start 
[ ok ] Starting periodic command scheduler: cron.

1分後…

cron.log
Running via Spring preloader in process 122

ついにcron.logが生成されlogが書かれました。
rails consoleで確認します。

root@827fe138767f:/myapp# bundle exec rails c
Running via Spring preloader in process 135
Loading development environment (Rails 5.2.4.3)
irb(main):001:0> Post.all.count
   (4.5ms)  SELECT COUNT(*) FROM "posts"
=> 1

データが生成されたのがわかりますね!

課題

しかしcronの起動は手動で毎回行うのは面倒なので、できればdockerfileに記述して自動で起動されるようにしたいところです。
今後その方法も追記していきたと思います。

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

dockerでMySQLのサンプルデータベースのSakilaを使用した環境をすぐ使用できるように設定してみた

私はdocker初心者です。間違いやもっと良い方法があれば教えていただけるとありがたいです。


SakilaとはMySQLが公式で用意しているサンプルデータベースです。

https://dev.mysql.com/doc/sakila/en/

こちらからダウンロードできます

https://dev.mysql.com/doc/index-other.html

DVDレンタル情報が保存されているデータベースで、個人的にはMySQLのデータを使って試したいときに使うというのが便利だと思います。

それをdockerでちょちょっと環境が作成できるようにやってみました。


参考

Dockerfile作成

mysqlの公式イメージを使ってDockerfileを設定してみました

Dockerfile
FROM mysql:8

ENV MYSQL_ROOT_PASSWORD=root

RUN apt-get update \
    && apt-get install -y wget unzip \
    && wget http://downloads.mysql.com/docs/sakila-db.zip \
    && unzip sakila-db.zip \
    # docker-entrypoint-initdb.d/ の .sql ファイルが自動でアルファベット順に実行されるので、リネームしつつ移動
    && mv sakila-db/sakila-schema.sql /docker-entrypoint-initdb.d/01_sakila-schema.sql \
    && mv sakila-db/sakila-data.sql /docker-entrypoint-initdb.d/02_sakila-data.sql

Dockerfileをビルドしてコンテナ作成

$ docker build -t sample .
(省略)
$ docker run --name sakila -d sample
(省略)
$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                 NAMES
a599ee328437        sample              "docker-entrypoint.s…"   About a minute ago   Up About a minute   3306/tcp, 33060/tcp   sakila

mysqlに接続しshow tables;を実行

$ docker container exec -it sakila mysql -uroot -proot -Dsakila
mysql: [Warning] Using a password on the command line interface can be insecure.
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 8.0.21 MySQL Community Server - GPL

Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show tables;
+----------------------------+
| Tables_in_sakila           |
+----------------------------+
| actor                      |
| actor_info                 |
| address                    |
| category                   |
| city                       |
| country                    |
| customer                   |
| customer_list              |
| film                       |
| film_actor                 |
| film_category              |
| film_list                  |
| film_text                  |
| inventory                  |
| language                   |
| nicer_but_slower_film_list |
| payment                    |
| rental                     |
| sales_by_film_category     |
| sales_by_store             |
| staff                      |
| staff_list                 |
| store                      |
+----------------------------+
23 rows in set (0.00 sec)

mysql> 

Sakilaのサンプルのdbが作成されていることを確認できました

phpmyadminでも見れるようにしてみた

先ほどのDockerfileと同じディレクトリにdocker-compose.ymlを作成

docker-compose.yml
version: "3"

services:
    db:
        build: .
        container_name: mysql

    phpmyadmin:
        container_name: phpmyadmin
        image: phpmyadmin/phpmyadmin
        environment:
            - PMA_ARBITRARY=1
            - PMA_HOST=mysql
            - PMA_USER=root
            - PMA_PASSWORD=root
        ports:
            - 8080:80
$ docker-compose up -d

http://localhost:8080/

Screen Shot 2020-08-03 at 0.59.40.png

以上です。

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