20200807のdockerに関する記事は11件です。

【ECS】ALBを通してnginx+php-fpm環境をECSで動かす

ゴール

下記で作成したコンテナへのアクセスにALBを使う。phpinfoが見られればOK
https://qiita.com/chanP_yamazaki/items/f4829a2905582a78223a

ALBとターゲットグループを作成する

手順 名称 設定値
ロードバランサーの設定 名前 ecs-cluster-alb
アベイラビリティーゾーン aとc両方にチェック
セキュリティグループの設定 セキュリティグループの割当 ポート80許可したものを設定 or 作成
ルーティングの設定 ターゲットグループ HTTP、ポート80のターゲットグループを作成or割当

ECSのタスクを定義する

※記載がないパラメータは変更しないものとする

・タスク名をつける
 後から変えられないので注意
・コンテナの追加
 これがまさにdocker-compose.ymlに相当している

 ▼ nginx

名称 設定値
コンテナ名 nginx
イメージ ECRにプッシュしたnginxコンテナの「イメージのURI」をコピーして貼り付け
メモリ制限 必要な分だけ設定。全コンテナの合計値がインスタンスのメモリサイズを超えないように注意
ポートマッピング 設定なし:80に設定する
スタートアップ依存順序 depends_on設定。コンテナ名「php-fpm」、状態「START」を設定
ネットワーク設定 リンクに「php-fpm:php-fpm」を設定
ストレージとログ ログ設定の「Auto-configure CloudWatch Logs」をONに (立ち上げに失敗した際にログを追えるようになる

 他は最小構成では設定不要

 ▼ php-fpm

名称 設定値
コンテナ名 php-fpm
イメージ ECRにプッシュしたphp-fpmコンテナの「イメージのURI」をコピーして貼り付け
メモリ制限 必要な分だけ設定。全コンテナの合計値がインスタンスのメモリサイズを超えないように注意
ポートマッピング php-fpmは外に開ける必要無いので設定不要
ストレージとログ ログ設定の「Auto-configure CloudWatch Logs」をONに (立ち上げに失敗した際にログを追えるようになる

 他は最小構成では設定不要

・他は設定せず作成

ECSクラスターを作成する

・Amazon Container Service -> Amazon ECS -> クラスター へ
・クラスターの作成

ステップ 名称 設定値
クラスターテンプレートの選択 クラスターテンプレートの選択 EC2 Linux + ネットワーキング
クラスターの設定 クラスター名 test-cluster
インスタンスの設定各種 インスタンスタイプや数は必要に応じて
AmiId 特に理由がなければ今は 「AmazonLinux2」
キーペア コンテナの思想上、インスタンスに入って何かを操作する必要はないので 「なし」 
ネットワーキング各種 vpc、サブネットは必要に応じた設定を
ネットワーキング - セキュリティグループ ポートは0-65535まで開ける。IPは必要なものを
Auto assign public IP Disabled

・作成実行
 実行したクラスターの「ECSインスタンス」タブで、指定した個数のインスタンスが立ち上がり、ステータスがACTIVEになったことを確認

コンテナを立ち上げる

・サービスタブを開いて「作成」

ステップ 名称 設定値
サービスの設定 起動タイプ EC2
タスク定義 ファミリー 先ほど「タスク定義」で作ったタスクを指定
タスク定義 リビジョン latest(最新バージョン)を指定
クラスター test-cluster
サービス名 適当に
サービスタイプ REPLICA (DAEMONだとどう変わるか後で調査
タスク数 1
ネットワーク構成 ロードバランサーの種類 ALBを指定
ネットワーク構成 ロードバランサー名 先ほど作成したもの
ネットワーク構成 ロードバランス用のコンテナ nginx:0:80 を追加
ネットワーク構成 プロダクションリスナーポート 80:HTTP
Auto Scalingオプション EC2インスタンスの数をAutoScalingさせたいならここで設定。今回は何も設定せず次へ

・サービスの作成
・作成したサービスのタスクタブにRUNNINGのタスクが出来あがれば成功
・ELBのpublicIPかDNS名にアクセスしてphpinfoが確認できればOK!

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

DockerでRailsチュートリアルのローカル開発環境構築 - WebpackでBootstrapとFont Awesomeを導入 -

はじめに

Dockerでローカル開発環境構築を行い、Railsチュートリアルを再走しております

  • Railsチュートリアル最新版(2020.8.6現在)に対応のRails 6
  • Dockerを使用し、開発環境の再現が可能
  • なるべくローカル環境にインストールしない

今回はRailsチュートリアルの5章に相当する部分です

3章, 4章の内容は特に問題になりませんが、

5章 5.1.2 BootstrapとカスタムCSS の部分でいよいよWebpackの沼に突入して行きます

具体的にはgemを利用せず, YarnとWebpackでBootstrapやFont Awesomeを導入、管理します

加えてテストを書くことが増えるのでその辺りをRSpecで置き換えて進めていきます

5章終了時のブランチはfilling-in-layoutです
https://github.com/dev-naokit/sample_app_on_docker/tree/filling-in-layout

第一回
DockerでRailsチュートリアルのローカル開発環境構築(Rails 6 + PostgreSQL + Webpack) - Qiita

第二回
DockerでRailsチュートリアルのローカル開発環境構築 - RSpec導入 & CircleCIでHerokuデプロイ- - Qiita

個人開発アプリ
mdClip <オンラインmarkdownエディタ>

Dockerのコンテナ上で操作する場合はターミナルのコマンドを適宜

$ docker-compose run app ...

もしくは

$ docker-compose exec app ...

で置き換えてください。

BootstrapとFontawesomeの導入

Rails 6ではJavaScriptのモジュールバンドラとしてWebpackが導入されていますが、
画像やCSSに関しては従来のSprocketがアセットパイプラインとして使用され、
JavaScriptのみをWebpackでコンパイルするようになっています

application.html.erb

<head>の内容を書き換えます

app/views/layouts/application.html.erb

<head>
  <title><%= full_title(yield(:title)) %></title>
  <%= csrf_meta_tags %>
  <%= csp_meta_tag %>
  <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
  # (下の行を追記)webpackがCSSを扱えるようにする
  <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
  # JavaScriptはデフォルトでwebpacerが pack フォルダをコンパイルして出力している
  <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  <!--[if lt IE 9]>
      <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
      </script>
    <![endif]-->
</head>

YarnでBootstrapをインストール

jquerypopperはBootstrapに必要なパッケージ
Font Awesomeもあとで必要になるのでインストールします
('@fortawesome'は誤字ではありません)

yarn add bootstrap jquery popper.js @fortawesome/fontawesome-free

インストールされたモジュールは
package.jsonで確認できます

application.js

app/javascript/packs/application.js

以下を追記します

require("bootstrap");
require("@fortawesome/fontawesome-free");

require('jquery')も併記するような情報もありましたが、
Bootstrapが自動的にrequire('jquery')してくれるようでココには記述不要です

私も色々不具合を検証している過程で
require('jquery')がなくてもjqueryがロードされることに気づいたのですが
jqueryの多重起動はJavaScriptの動作不具合につながることもあるようで、
現状はこのまま進めます

(下に参考記事を貼っておきます)

environment.js

jQueryをどこからでも呼び出せるようにする

config/webpack/environment.js

const { environment } = require('@rails/webpacker')
var webpack = require('webpack');

environment.plugins.append(
    'Provide',
    new webpack.ProvidePlugin({
        $: 'jquery/src/jquery',
        jQuery: 'jquery/src/jquery',
        Popper: ['popper.js', 'default']
    })
)

module.exports = environment

こうすることで毎回import $ from 'jquery';と書かなくて良くなるとのことです

CSS

app/javascript/stylesheets/application.scss(新規作成)

以下追記

@import '@fortawesome/fontawesome-free/scss/fontawesome';
@import 'bootstrap/scss/bootstrap';

application.js

app/javascript/packs/application.js

以下を追記します

import '@fortawesome/fontawesome-free/js/all';
import "../stylesheets/application.scss";

参考

Rails 6: Webpacker+Yarn+Sprocketsを十分理解してJavaScriptを書く: 前編(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社

Rails 6+Webpacker開発環境をJS強者ががっつりセットアップしてみた(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社

CSSの扱いについて

JavaScriptだけでなく画像やCSS、全てをWebpackでコンパイルすることも可能なようです

現状はSprocketによるアセットコンパイルと、Webpackerが共存している状況に変わりはなく

app/javascript/stylesheets/...をコンパイルした内容が<head>内の

<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>

で出力され

app/assets/stylesheets/...をコンパイルした内容が同じく<head>内の

  <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>

に出力されている状況です

つまりチュートリアル通りassets内のCSS, SCSSを編集しても、
packs内のCSS, SCSSを編集してもビューに反映される状況が出来上がっています

BootstrapやFont Awesomeのstyleは後者によってimportされ、コンパイル、ビューに反映されています

今後チュートリアルをすすめる上でどちらのStylesheetを編集しても問題ないと思いますが
<head>内での呼び出しの順序くらいは気に留めて置いたほうがいいかもしれません

ちなみに、packs内でCSSを編集する場合、webpack-dev-serverのHot reloadの恩恵を受けられます
具体的には、変更保存した場合に自動的にブラウザがリロードされ、即座に(やや遅延あり...)変更内容を確認できます

Railsチュートリアルの流れでcustom.scssを作成する場合
app/javascript/packs/application.jsに以下を記述すれば大丈夫です

import "../stylesheets/custom.scss";

(私はこの仕様で進めてみます)

Troubleshoot

Bootstrapのスタイルがおかしい

おそらくヘッダー周りが上手く表示されないと思います
Bootstrapのバージョンの違いによるものでこちらの記事の通りインストールすると
Bootstrapの最新版ver. 4.5(2020.8.7現在)が導入されます
(Railsチュートリアルでは3.4.1)

navbar-inverseというタグがBootstrap 4では使用できなくなっていますので

  <header class="navbar navbar-expand-md bg-dark navbar-dark bg-dark">

で置き換えるなど細かな修正が必要です
修正を加えたこの章終了時のBranchを公開する予定ですが

yarn addの際にバージョンを指定するといった対策も可能です

テストRSpec関連

assert_...をどう書き換えるか?

そのまま使えます

「RSpecでも assert xxx って書いてテストしたい」=> すぐできます! - Qiita

ApplicationHelperをテストでも使えるように...

include ApplicationHelperを個別の_spec.rbファイルに記述

もしくは、spec/rails_helper.rbに記述
_spec.rbでrequireされているので、個々に記述する必要はないはずです

おわりに

この部分はRails 6環境で個人アプリ開発にあたり、最も苦労しました

身の丈に合わない内容で誤りを含むかもしれませんが

Railsチュートリアルの環境構築だけでなく、Rails 6環境でアプリ開発を行う方の一助になれば幸いです

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

DockerでCentOS7 + Apache2.4環境をサクッと構築してみる。

身の回りでDockerやLinuxの勉強したい!って人がちょいちょいいたので、勉強用にサクッと出来る手順をまとめました。

環境

  • Windows for Docker
  • CentOS7
  • Apache2.4

手順

(前提)Windows for Dockerは既に準備済みとします。

1.CentOS7のイメージを入手する

$ docker pull centos:7

2.CentOS7のイメージからコンテナを作成する

$ docker run -d -p 80:80 --name apache-test centos:7
abe8af3f37a4f3ea1b0dd169b0039bd485b49f5689e4c4a6042a3b5ea5107c6e
$ docker ps -a
CONTAINER ID        IMAGE                                COMMAND                  CREATED             STATUS                     PORTS                               NAMES
b570f5458b41        centos:7                             "/bin/bash"              4 seconds ago       Exited (0) 3 seconds ago                                       apahce-test

作成できてますね。

3.Apacheの準備・動作確認を行う。

コンテナの中に入って、Apache2.4のインストール→動作確認を行います。

$ docker exec -it apache-test /bin/bash
[root@80f5725a647a /]#

無事入ることができましたので、 yum updateを行い、httpdをインストールしていきます。

# yum update -y
# yum install -y httpd
# httpd -v
Server version: Apache/2.4.6 (CentOS)
Server built:   Apr  2 2020 13:13:23

バージョン情報が出たので無事にインストール出来たことが確認できました。
では実際にアクセスしてみます。

image1.png
http://[Docker for Windowsを起動した時に出てくる赤枠のIPアドレス]にアクセスします。

image1.png
無事にアクセスすることができました。

余談

CentOS7+Apache2.4の環境ではないですが、さっくりWebサーバを立てたいだけであれば、Docker公式Hubからイメージをpullして動かすのが最速です。

$ docker pull httpd
$ docker images
REPOSITORY                           TAG                 IMAGE ID            CREATED             SIZE
httpd                                latest              a6ea92c35c43        29 hours ago        166MB
$ docker run -d -p 80:80 httpd-test httpd
$ docker start httpd-test
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker SDK & Go言語 を使ってAWS ECRのimageをpull & run する

「AWS ECRにログインして docker imageを pullし、docker runする」

このような作業はあまりプロダクションで手動でやることはありませんが、やるとすれば普通に aws-cliを使ってECRにLogin, 後は dockerコマンドでの作業となるかと思います。

ところで、Go製であるDockerには公式SDKがあります。
今回とある事情があり、 github.com/aws/aws-sdk-gogithub.com/docker/docker を使って上記の作業をGoのコードのみでやる機会がありました。

Develop with Docker Engine SDKs
Examples using the Docker Engine SDKs and Docker API

ググっても出てこないくらい触らなそうな作業ではありますが、どこかの誰かのためにサンプルコードを置いておきます。

package main

import (
    "context"
    "encoding/base64"
    "encoding/json"
    "fmt"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/ecr"
    "github.com/docker/docker/api/types"
    "github.com/docker/docker/api/types/container"
    "github.com/docker/docker/api/types/mount"
    "github.com/docker/docker/client"
    "github.com/labstack/gommon/log"
    "io"
    "os"
    "strings"
    "time"
)

func main() {

    auth := getEcrRegistryAuth()
    pullAndRunContainer(auth)

}

func getEcrRegistryAuth() string {

    /*  ECR Login  */
    sess := session.Must(session.NewSessionWithOptions(session.Options{
        SharedConfigState: session.SharedConfigEnable,
    }))

    ecrSdk := ecr.New(sess)
    authOutput, err := ecrSdk.GetAuthorizationToken(&ecr.GetAuthorizationTokenInput{})
    if err != nil {
        log.Panic(err)
    }

    token := authOutput.AuthorizationData[0].AuthorizationToken

    authStr := aws.StringValue(token)
    decoded, err := base64.StdEncoding.DecodeString(authStr) // Decode the Base64 encoded token
    if err != nil {
        log.Panic(err)
    }
    password := strings.ReplaceAll(string(decoded), "AWS:", "")

    jsonBytes, _ := json.Marshal(map[string]string{
        "username": "AWS",
        "password": password,
    })

    return base64.StdEncoding.EncodeToString(jsonBytes)

}

func pullAndRunContainer(auth string) {

    imageUri := `xxxxxxxxxxxxxxxxx.dkr.ecr.ap-northeast-1.amazonaws.com/my-ecr:latest`
    containerName := fmt.Sprintf(`test-container-%v`, time.Now().UnixNano())

    ctx := context.Background()

    cli, err := client.NewEnvClient()
    if err != nil {
        log.Fatal(err)
    }

    reader, err := cli.ImagePull(ctx, imageUri, types.ImagePullOptions{
        RegistryAuth: auth,
    })
    if err != nil {
        log.Panic(err)
    }
    io.Copy(os.Stdout, reader)

    cont, err := cli.ContainerCreate(
        ctx,
        &container.Config{
            Image: imageUri,
            Cmd: []string{
                `sh`,
                `-c`,
                `echo "Run App !!!!!"`,
            },
            Env: []string{
                "PASS=xxxxxxxxxxxxxx", // いいのか?
            },
            //Cmd:   command,
        }, &container.HostConfig{
            Mounts: []mount.Mount{
                {
                    Type:   mount.TypeBind,
                    Source: "<HostのMount Dir>",
                    Target: "/mnt", // gyao_yvpub_wrapper内のmount dir
                },
            },
        }, nil, containerName)
    if err := cli.ContainerStart(ctx, cont.ID, types.ContainerStartOptions{}); err != nil {
        log.Panic(err)
    }

    go func() {
        out, logErr := cli.ContainerLogs(ctx, cont.ID, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true})
        if logErr != nil {
            log.Error(logErr)
        }
        containerLog := streamToString(out)
        fmt.Println(containerLog)
    }()

    exitCode, err := cli.ContainerWait(ctx, cont.ID)
    if err != nil {
        log.Fatal(err)
    }

    if exitCode != 0 {
        log.Error(err)

        out, logErr := cli.ContainerLogs(ctx, cont.ID, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true})
        if logErr != nil {
            log.Error(err)
        }

        containerLog := streamToString(out)
        fmt.Println(containerLog)
    }

}


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

docker をキャッシュを使わないでビルドする

docker build時に参照ファイルを更新したにもかかわらず、docker build時に反映されない場合はキャッシュクリアすると良い。

docker build . --no-cache

docker-composeを使う場合は以下

docker-compose build --no-cache

参考

Dockerのビルド時にGithubのプライベートリポジトリをcloneする

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

502エラーで困った話

502(Bad Gateway)嫌い

フロントのフレームワークの勉強をしていてバック側で作成したapiを叩いてみたら502エラー

エラー内容

502(Bad Gateway)
upstream sent too big header while reading response header from upstream

問題:

chromeからurl直打ちでgetすると正常に表示される*のですが、
vue側でaxios.getを行うと502(bad gateway)エラーになります。

エラーが発生した環境

  • docker仮想環境
  • フロントエンド:Vue.js 2.6
  • バックエンド :Laravel 7
  • dockerコンテナ:nginx, php-fpm

原因:

  1. upstream sent too big header while reading response header from upstream
  2. PCのスペック不足による仮想サーバのダウン

解決:

  1. upstream sent too big header while reading response header from upstream

簡単な通信を行っているのでバッファを大きくする必要はなさそう。。
(一応言われたとおりにnginxとphp-fpmのレスポンスヘッダのためのバッファサイズをこの記事を参考に大きく確保しました。)

→これでは解決せず


  1. PCのスペック不足による仮想サーバのダウン

これが一番ありそうだったのでPCを再起動後もう一度検証してみたらエラー出ませんでした。

→解決(?)

他に原因かもしれないこと

  • ⌘ + shift + R (リソースから直接読み込み)だと100%502エラーになる
    → 複数リクエストが原因?
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DockerでのディープラーニングGPU学習環境構築方法

DockerでGPU学習環境構築

背景

 ディープラーニングでローカルPCのGPUを使った学習環境を構築した経験のある人は、一度はNVIDIAのドライバやCUDA周りでハマった経験があるのではないでしょうか?そんなバッドノウハウ(怪文章?)をまとめたQiita記事(TensorFlowでGPU学習させるためにCUDA周りではまったときの対処法)に、なんとNVIDIAの中の人(@ksasaki さん)から「Dockerを使えば…人類は幸せになれる(超意訳)」とのコメントをいただきました!

 喜び勇んで、NVIDIAのドライバをアップデートしたところ、そこには文鎮と化した起動しないLinuxマシンが…からあげのNVIDIAとの戦いは始まったばかりだ!(戦ってません)

DockerでGPU学習環境構築するメリット

 うまく構築できればという前提で、以下のようなメリットがあります。

  • 様々なフレームワーク(TensorFlow/PyTorch)、バージョンの使い捨ての学習環境を一瞬で構築できる
  • クラウド環境での学習環境構築にもそのまま使える

 Docker自体の説明や、メリットに関しては以下記事を参照ください。
Docker入門して機械学習環境構築

 ただ、やってみるとハマりどころは結構あるので、2桁回くらいUbuntuを再セットアップすることになりました。その過程で得た、闇の知識をここで惜しげも無く公開したいと思います。

この記事の前提(必要なもの)

  • 基礎的なコマンドの知識
  • Ubuntuをインストールするマシン
  • USBメモリ
  • Ubuntuのバージョンは18.04を想定(16.04でも一応OK)
  • 黒画やログインループでめげない強い心

 使用したハードウェアは、HP ZBOOK、GPUはQuadro P600です。最新のいけてるGPUなら、ハマる確率は小さいのではないかと思います。

DockerでのGPU学習環境構築の流れ

 以下の6つを実施すればOKです。

  • Ubuntuインストール
  • セキュアブートの無効化
  • nouveauの停止
  • NVIDIAドライバのインストール
  • NVIDIAドライバの確認
  • DockerとNVIDIA Container Toolkit(旧 NVIDIA-Docker)のセットアップ

 Dockerを使うことで、CUDA、cuDNN、TensorFlowのバージョンの組み合わせに悩まなくて済むのが良いですね。

 順に説明していきます。

Ubuntuインストール

 Ubuntu 18.04を前提としています。Ubuntuは以下からイメージをダウンロードします。

Ubuntu 18.04イメージ

 イメージをbalenaEtcherというソフトを使用してUSBメモリに書き込みます。balenaEtcherのサイトからダウンロードしてインストールします。

 USBメモリをPCに繋いだ状態でbalenaEtherを起動して、以下のようにイメージを選択、USBメモリを選択、Flashをクリックするだけです。

 2019-07-05 1.12.45.png

 USBメモリからのUbuntuのセットアップ方法は省略します(調べたら色々情報出てくると思います)。

セキュアブートの無効化

 BIOSのセキュアブートは無効化しないと、後々NVIDIAのドライバを確認するnvidia-smiコマンドで以下のようなエラーメッセージが出てしまいます。必ず実施しましょう(サボってハマりました)。

NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.

 PCによって方法が異なりますので手順は割愛します。BIOSを起動して、Secure BootをDisableにするのが基本です。

 Secureブートが無効化されたかは、Ubuntuのターミナルで以下のコマンドを実行して確認できます。

$ dmesg | grep Secure

 以下のようにSecure boot disabledと表示されたらOKです。

[    0.000000] secureboot: Secure boot disabled
...

nouveauの停止

 NVIDIAのドライバにとって邪魔なグラフィックドライバであるnoveauを停止します。以下でnouveauが動いているか確認します。

$ lsmod | grep -i nouveau

 以下のように表示されたら、nouveauが動いています。

nouveau              1896448  1
mxm_wmi                16384  1 nouveau
ttm                   102400  1 nouveau
drm_kms_helper        184320  2 i915,nouveau
drm                   491520  8 drm_kms_helper,i915,ttm,nouveau
i2c_algo_bit           16384  2 i915,nouveau
wmi                    32768  5 hp_wmi,intel_wmi_thunderbolt,wmi_bmof,mxm_wmi,nouveau
video                  49152  2 i915,nouveau

 止めるために、以下の設定ファイルを作成します。

$ sudo vi /etc/modprobe.d/blacklist-nvidia-nouveau.conf

 blacklist-nvidia-nouveau.confの中身は以下にしてください。

blacklist nouveau
options nouveau modset=0

 以下コマンドで設定を有効します。

$ sudo update-initramfs -u

再起動しないまま次に進みます(NVIDIAドライバをインストールしないまま再起動すると画面が崩れる可能性があります)。

NVIDIAドライバのインストール

 自動でインストールする方法と手動(apt)でインストールする方法の2つがあります。自動が楽で良いですが、ダメだった場合のために、手動の方法も説明します。

 自分の環境では、Ubuntuセットアップ直後で自動でインストールする方法が一番良かったです(他は全部ダメで、Ubuntu再インストールし続けました)。

自動でインストール

 最初に、なるべく新しいドライバをインストールしたい場合は、以下コマンドであらかじめPPAパッケージのリストを追加しましょう。ただしPPAなので自己責任で。

$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt update

 Ubutu 18.04以降は以下コマンドで自動でセットアップできます。

$ sudo ubuntu-drivers autoinstall
$ sudo shutdown -r now

 古いUbuntuの場合は、ubuntu-driversがありませんが、以下コマンドでubuntu-driversをインストールできると思います(未確認)。

$ sudo apt install ubuntu-drivers-common

 これでうまくいかない場合(黒画など)は、手動でインストールを試してみましょう。

手動(apt)でインストール

 最初にインストールするべきドライバを確認します。以下のコマンドで推奨のドライバがリストアップされます。

$ ubuntu-drivers devices 

以下は表示例です。recommendedとあるやつが推奨ドライバです(多分)。

ubuntu-drivers devices
== /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0 ==
modalias : pci:v000010DEd00001CBCsv0000103Csd0000847Bbc03sc00i00
vendor   : NVIDIA Corporation
driver   : nvidia-driver-440-server - distro non-free recommended
driver   : nvidia-driver-390 - distro non-free
driver   : nvidia-driver-435 - distro non-free
driver   : nvidia-driver-410 - third-party free
driver   : nvidia-driver-440 - distro non-free
driver   : nvidia-driver-418-server - distro non-free
driver   : xserver-xorg-video-nouveau - distro free builtin

 ubuntu-driversを使えない場合は、自分のGPUの型番を以下コマンドで調べてから、NVIDIAのサイトで対象のドライバを検索しましょう。

$ sudo lshw -C display

 あとはaptでお目当てのドライバをインストールしましょう。xxxには自分のセットアップしたいバージョンを指定しましょう(TABで候補が出てきます)。

$ sudo apt install nvidia-driver-xxx

 より新しいドライバをインストールしたい場合は、自動でインストールする場合と同様、以下コマンドでPPAパッケージのリストを追加しましょう。

$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt update

 あとは、再起動します。祈るように起動を待ちましょう。

$ sudo shutdown -r now

 再起動して無事起動画面が表示されたらOKです。おめでとうございます。

 不幸にも黒画になったり、起動しなかった場合は残念でした。頑張って修復するか、もういちどUbuntuインストールから始めましょう。NVIDIAのドライバを変えると起動するようになるかもしれません。

 この後、Dockerを動かすとき、最新のイメージほどホスト側のPCの最新のNVIDIAドライバが必要とされます。NVIDIAのドライバが対応していないと、Dockerを動かしたとき、以下のように「NVIDIAのドライバのバージョンが古いよ!」と怒られてしまいます

ERROR: This container was built for NVIDIA Driver Release 450.51 or later, but
       version 440.95.01 was detected and compatibility mode is UNAVAILABLE.

NVIDIA ドライバの確認

 再起動した後、正しくドライバがインストールされているかを確認します。その前に nouveau が停止しているかを確認しましょう。以下を実行して何も表示されなければOKです。

$ lsmod | grep -i nouveau

続いて以下のコマンドでNVIDIAのドライバ情報を確認します。

$ nvidia-smi

 以下のようにドライバのバージョンが表示されたらOKです。450のバージョンだとXがどうしても表示できないため、しかたなく440のバージョンに落としています。CUDA 10.2が表示されていますが、何かの間違いでしょう(インストールしていないので)。

+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.95.01    Driver Version: 440.95.01    CUDA Version: 10.2     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Quadro P600         Off  | 00000000:01:00.0 Off |                  N/A |
| N/A   57C    P0    N/A /  N/A |    476MiB /  4040MiB |      2%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0      1143      G   /usr/lib/xorg/Xorg                           335MiB |
|    0      1427      G   /usr/bin/gnome-shell                         137MiB |
+-----------------------------------------------------------------------------+

CUDAの正確な情報を知りたい場合はnvccを使いましょう。以下はnvccで確認する方法です(nvccでの確認に関しては、飛ばしてもOKです)。

 aptでnvidia-cuda-toolkitをインストールします。

$ sudo apt install nvidia-cuda-toolkit

 あとは、以下コマンドでCUDAの情報を取得できます。

$ nvcc -V

 何故かこちらではCUDA9.1がインストールされていることになっています。謎ですね…

nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2017 NVIDIA Corporation
Built on Fri_Nov__3_21:07:56_CDT_2017
Cuda compilation tools, release 9.1, V9.1.85

 気にせず(オイ)次にいきましょう。誰か詳しい人は教えてください…

DockerとNVIDIA Container Toolkit(NVIDIA Docker)のインストール

 DockerとDockerでGPUを使うために必要なNVIDIA Container Toolkitをインストールします。参考までに、少し古いNVIDIA Docker(公式ではNVIDIA Container Toolkitが推奨されています)のセットアップ方法も記載します。

Dockerのインストール

 UbuntuにDockerをインストールします。オフィシャルの手順がやや煩雑なので手軽にセットアップできるスクリプト用意しました。

 最初にcurlをインストールします

$ sudo apt install -y curl

 その後、以下のコマンドを実行すればoKです。

$ curl -s https://raw.githubusercontent.com/karaage0703/ubuntu-setup/master/install-docker.sh | /bin/bash

 ここで、権限を有効にするために、一旦再起動しましょう(再ログインで良いはずなのですが、私の環境では駄目だったため再起動しました)。

$ sudo shutdown -r now

NVIDIA Container Toolkitのインストール

NVIDIAのnvidia-container-toolkitパッケージをインストールします。Quickstartの手順をスクリプト化したので、以下の通り実行すればOKです。

$ curl -s https://raw.githubusercontent.com/karaage0703/ubuntu-setup/master/install-nvidia-container-toolkit.sh | /bin/bash

 続いてDockerを起動するため、以下コマンド実行すると…

$ docker run --gpus all --rm nvidia/cuda nvidia-smi
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449: container init caused \"process_linux.go:432: running prestart hook 0 caused \\\"error running hook: exit status 1, stdout: , stderr: nvidia-container-cli: requirement error: unsatisfied condition: cuda>=11.0, please update your driver to a newer version, or use an earlier cuda container\\\\n\\\"\"": unknown.

 cudaがどうこう言われてダメでした…NVIDIAのドライバが古いのでしょうか…

 とりあえず、TensorFlow公式のDockerイメージで試してみます。以下コマンドでDockerを動かします。

$ docker run --gpus all -it --rm --name tensorflow-gpu -p 8888:8888 tensorflow/tensorflow:latest-gpu-py3-jupyter

 実行すると勝手にイメージのダウンロードが始まり、ダウンロードが完了するとコンテナが起動します。起動すると画面に token=xxxxxxxxxxxxxx という形でtokenが表示されます。

 続いて、ブラウザで以下のアドレスにアクセスしましょう。tokenの後は、先ほど表示されたtokenを入力します。

http://127.0.0.1:8888/?token=xxxxxxxxxxxxxx

 Jupyter Notebookにアクセスできました。

jupyter_notebook.png

 以下コマンド実行して、上図のようにGPUが表示されたらOKです。

from tensorflow.python.client import device_lib
device_lib.list_local_devices()

 何か動かしてみたい人は、tensorflow-tutorialというディレクトリの中に、色々なサンプルが入っているのでMNISTあたりを動かしてみると良いと思います。nvidia-smiを起動すれば、メモリが消費されてちゃんとGPUが動いていることが確認できます。

+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.95.01    Driver Version: 440.95.01    CUDA Version: 10.2     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Quadro P600         Off  | 00000000:01:00.0 Off |                  N/A |
| N/A   55C    P0    N/A /  N/A |   3874MiB /  4040MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

NVIDIA-Docker

 参考までにNVIDIA-Dockerのインストール方法を紹介します。繰り返しになりますが、NVIDIA-Dockerは古いバージョンとなり、公式はNVIDIA Container Toolkitを推奨していますので、特別な理由がなければNVIDIA Container Toolkitを利用ください。

 こちらも公式サイトのREADMEをもとに、セットアップスクリプト作成しました。以下コマンドでインストールできます。

$ curl -s https://raw.githubusercontent.com/karaage0703/ubuntu-setup/master/install-nvidia-docker.sh | /bin/bash

 以下のnvidia-dockerコマンドで、同様に動かせます。

$ nvidia-docker run -it --rm --name tensorflow-gpu -p 8888:8888 tensorflow/tensorflow:latest-gpu-py3-jupyter

NVIDIAの提供しているNGCイメージ

 NVIDAの提供しているNGCのTensorFlow イメージが良いという話を聞いたので試してみました。

 tensorflow-release-notesをみて、NVIDIAドライバのバージョンが対応しているイメージを探します(Driver Requirementsのところに書かれています)。私がインストールしている NVIDIAのドライバ440.95.01の場合だと、20.03が対応していたので、以下の通り実行してみます。

$ docker run --gpus all --rm -it nvcr.io/nvidia/tensorflow:20.03-tf1-py3

 一瞬起動画面は出るのですが、Dockerにログインできず…他のバージョンもいくつか試してみましたがダメでした・・・残念ながら諦めました。原因はわかりませんでした。NVIDIAのドライバの関係でしょうか…?

 コメントのアドバイス通り、オプションを修正することで無事Dockerにログインできました!NGCイメージは、TensorFlowはもちろん、TensorRTやDALI、豊富なサンプル、Jupyter Labなどが含まれていて便利そうです。

黒画になってしまった場合

 とりあえずリカバリーモードでログインするのが良いです。起動時に「ESC」連打で入れます。

 「ESC」でブート選択画面になるPCの場合は、Continue boot(ブートを続ける)選択をした直後に「ESC」を1回押すと入れたりします。

 rootでCUI画面に入ったら、以下でドライバを削除すると黒画から脱出できたりします。

$ sudo apt --purge autoremove nvidia*

 どうしてもダメなら、素直に再インストールすれば良いと思います。

まとめ

 DockerでディープラーニングのGPU学習環境構築する方法を書きました。色々ハマってしまったので無駄に長くなってしまいました。

 Dockerは、数年前から「便利そうだから使ってみよう!」 → 「やっぱり自分には早かった」を繰り返しているような気がしますが、使いこなせれば、CUDAとTensorFlowのバージョン違いに悩まされなくなったり、色々な環境で素早く試したりができたりするので、なんとか使いこなしていきたいなと思います。

関連ページ

TensorFlowでGPU学習させるためにCUDA周りではまったときの対処法

Docker入門して機械学習環境構築

参考リンク

変更履歴

  • 2020/08/08 コメントのアドバイスを受けて、NVIDIA DockerとNGCイメージに関して文章修正
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DockerでディープラーニングのGPU学習環境構築方法

DockerでGPU学習環境構築

背景

 ディープラーニングでローカルPCのGPUを使った学習環境を構築した経験のある人は、一度はNVIDIAのドライバやCUDA周りでハマった経験があるのではないでしょうか?そんなバッドノウハウ(怪文章?)をまとめたQiita記事(TensorFlowでGPU学習させるためにCUDA周りではまったときの対処法)に、なんとNVIDIAの中の人(@ksasaki さん)から「Dockerを使えば…人類は幸せになれる(超意訳)」とのコメントをいただきました!

 喜び勇んで、NVIDIAのドライバをアップデートしたところ、そこには文鎮と化した起動しないLinuxマシンが…からあげのNVIDIAとの戦いは始まったばかりだ!(戦ってません)。

DockerでGPU学習環境構築するメリット

 うまく構築できればという前提で、以下のようなメリットがあります。

  • 様々なフレームワーク(TensorFlow/PyTorch)、バージョンの使い捨ての学習環境を一瞬で構築できる
  • クラウド環境での学習環境構築にもそのまま使える

 Docker自体の説明や、メリットに関しては以下記事を参照ください。
Docker入門して機械学習環境構築

 ただ、やってみるとハマりどころは結構あるので、2桁回くらいUbuntuを再セットアップすることで得た闇の知識をここで惜しげも無く公開したいと思います。

この記事の前提(必要なもの)

  • 基礎的なコマンドの知識
  • Ubuntuをインストールするマシン
  • USBメモリ
  • Ubuntuのバージョンは18.04を想定(16.04でも一応OK)
  • 黒画やログインループでめげない強い心

 使用したハードウェアは、HP ZBOOK、GPUはQuadro P600です。最新のいけてるGPUなら、ハマる確率は小さいのではないかと思います。

DockerでのGPU学習環境構築の流れ

 以下の6つを実施すればOKです。

  • Ubuntuインストール
  • セキュアブートの無効化
  • nouveauの停止
  • NVIDIAドライバのインストール
  • NVIDIAドライバの確認
  • DockerとNVIDIA Container Toolkit(旧 NVIDIA-Docker)のセットアップ

 Dockerを使うことで、CUDA、cuDNN、TensorFlowのバージョンの組み合わせに悩まなくて済むのが良いですね。

 順に説明していきます。

Ubuntuインストール

 Ubuntu 18.04を前提としています。Ubuntuは以下からイメージをダウンロードします。

Ubuntu 18.04イメージ

 イメージをbalenaEtcherというソフトを使用してUSBメモリに書き込みます。balenaEtcherのサイトからダウンロードしてインストールします。

 USBメモリをPCに繋いだ状態でbalenaEtherを起動して、以下のようにイメージを選択、USBメモリを選択、Flashをクリックするだけです。

 2019-07-05 1.12.45.png

 USBメモリからのUbuntuのセットアップ方法は省略します(調べたら色々情報出てくると思います)。

セキュアブートの無効化

 BIOSのセキュアブートは無効化しないと、後々NVIDIAのドライバを確認するnvidia-smiコマンドで以下のようなエラーメッセージが出てしまいます。必ず実施しましょう(サボってハマりました)。

NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.

 PCによって方法が異なりますので手順は割愛します。BIOSを起動して、Secure BootをDisableにするのが基本です。

 Secureブートが無効化されたかは、Ubuntuのターミナルで以下のコマンドを実行して確認できます。

$ dmesg | grep Secure

 以下のようにSecure boot disabledと表示されたらOKです。

[    0.000000] secureboot: Secure boot disabled
...

nouveauの停止

 NVIDIAのドライバにとって邪魔なグラフィックドライバであるnoveauを停止します。以下でnouveauが動いているか確認します。

$ lsmod | grep -i nouveau

 以下のように表示されたら、nouveauが動いています。

nouveau              1896448  1
mxm_wmi                16384  1 nouveau
ttm                   102400  1 nouveau
drm_kms_helper        184320  2 i915,nouveau
drm                   491520  8 drm_kms_helper,i915,ttm,nouveau
i2c_algo_bit           16384  2 i915,nouveau
wmi                    32768  5 hp_wmi,intel_wmi_thunderbolt,wmi_bmof,mxm_wmi,nouveau
video                  49152  2 i915,nouveau

 止めるために、以下の設定ファイルを作成します。

$ sudo vi /etc/modprobe.d/blacklist-nvidia-nouveau.conf

 blacklist-nvidia-nouveau.confの中身は以下にしてください。

blacklist nouveau
options nouveau modset=0

 以下コマンドで設定を有効します。

$ sudo update-initramfs -u

再起動しないまま次に進みます(NVIDIAドライバをインストールしないまま再起動すると画面が崩れる可能性があります)。

NVIDIAドライバのインストール

 自動でインストールする方法と手動(apt)でインストールする方法の2つがあります。自動が楽で良いですが、ダメだった場合のために、手動の方法も説明します。

 自分の環境では、Ubuntuセットアップ直後で自動でインストールする方法が一番良かったです(他は全部ダメで、Ubuntu再インストールし続けました)。

自動でインストール

 最初に、なるべく新しいドライバをインストールしたい場合は、以下コマンドであらかじめPPAパッケージのリストを追加しましょう。ただしPPAなので自己責任で。

$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt update

 Ubutu 18.04以降は以下コマンドで自動でセットアップできます。

$ sudo ubuntu-drivers autoinstall
$ sudo shutdown -r now

 古いUbuntuの場合は、ubuntu-driversがありませんが、以下コマンドでubuntu-driversをインストールできると思います(未確認)。

$ sudo apt install ubuntu-drivers-common

 これでうまくいかない場合(黒画など)は、手動でインストールを試してみましょう。

手動(apt)でインストール

 最初にインストールするべきドライバを確認します。以下のコマンドで推奨のドライバがリストアップされます。

$ ubuntu-drivers devices 

以下は表示例です。recommendedとあるやつが推奨ドライバです(多分)。

ubuntu-drivers devices
== /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0 ==
modalias : pci:v000010DEd00001CBCsv0000103Csd0000847Bbc03sc00i00
vendor   : NVIDIA Corporation
driver   : nvidia-driver-440-server - distro non-free recommended
driver   : nvidia-driver-390 - distro non-free
driver   : nvidia-driver-435 - distro non-free
driver   : nvidia-driver-410 - third-party free
driver   : nvidia-driver-440 - distro non-free
driver   : nvidia-driver-418-server - distro non-free
driver   : xserver-xorg-video-nouveau - distro free builtin

 ubuntu-driversを使えない場合は、自分のGPUの型番を以下コマンドで調べてから、NVIDIAのサイトで対象のドライバを検索しましょう。

$ sudo lshw -C display

 あとはaptでお目当てのドライバをインストールしましょう。xxxには自分のセットアップしたいバージョンを指定しましょう(TABで候補が出てきます)。

$ sudo apt install nvidia-driver-xxx

 より新しいドライバをインストールしたい場合は、自動でインストールする場合と同様、以下コマンドでPPAパッケージのリストを追加しましょう。

$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ sudo apt update

 あとは、再起動します。祈るように起動を待ちましょう。

$ sudo shutdown -r now

 再起動して無事起動画面が表示されたらOKです。おめでとうございます。

 不幸にも黒画や起動しなかった場合は残念でした。頑張って修復するか、もういちどUbuntuインストールから始めましょう。NVIDIAのドライバを変えると起動するようになるかもしれません。

 この後、Dockerを動かすとき、最新のイメージほどホスト側のPCの最新のNVIDIAドライバが必要とされます。NVIDIAのドライバが対応していないと、Dockerを動かしたとき、以下のように「NVIDIAのドライバのバージョンが古いよ!」と怒られてしまいます

ERROR: This container was built for NVIDIA Driver Release 450.51 or later, but
       version 440.95.01 was detected and compatibility mode is UNAVAILABLE.

NVIDIA ドライバの確認

 再起動した後、正しくドライバがインストールされているかを確認します。その前に nouveau が停止しているかを確認しましょう。以下を実行して何も表示されなければOKです。

$ lsmod | grep -i nouveau

続いて以下のコマンドでNVIDIAのドライバ情報を確認します。

$ nvidia-smi

 以下のようにドライバのバージョンが表示されたらOKです。450のバージョンだとXがどうしても表示できないため、しかたなく440のバージョンに落としています。CUDA 10.2が表示されていますが、何かの間違いでしょう(インストールしていないので)。

+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.95.01    Driver Version: 440.95.01    CUDA Version: 10.2     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Quadro P600         Off  | 00000000:01:00.0 Off |                  N/A |
| N/A   57C    P0    N/A /  N/A |    476MiB /  4040MiB |      2%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0      1143      G   /usr/lib/xorg/Xorg                           335MiB |
|    0      1427      G   /usr/bin/gnome-shell                         137MiB |
+-----------------------------------------------------------------------------+

CUDAの正確な情報を知りたい場合はnvccを使いましょう。以下はnvccで確認する方法です(nvccでの確認に関しては、飛ばしてもOKです)。

 aptでnvidia-cuda-toolkitをインストールします。

$ sudo apt install nvidia-cuda-toolkit

 あとは、以下コマンドでCUDAの情報を取得できます。

$ nvcc -V

 何故かこちらではCUDA9.1がインストールされていることになっています。謎ですね…

nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2017 NVIDIA Corporation
Built on Fri_Nov__3_21:07:56_CDT_2017
Cuda compilation tools, release 9.1, V9.1.85

 気にせず(オイ)次にいきましょう。誰か詳しい人は教えてください…

DockerとNVIDIA Container Toolkit(NVIDIA Docker)のインストール

 DockerとNVIDIA Container Toolkitをインストールします。参考までに、少し古いNVIDIA Docker2のセットアップ方法も記載します。

Dockerのインストール

 UbuntuにDockerをインストールします。オフィシャルの手順がやや煩雑なので手軽にセットアップできるスクリプト用意しました。

 最初にcurlをインストールします

$ sudo apt install -y curl

 その後、以下のコマンドを実行すればoKです。

$ curl -s https://raw.githubusercontent.com/karaage0703/ubuntu-setup/master/install-docker.sh | /bin/bash

 ここで、権限を有効にするために、一旦再起動しましょう(再ログインで良いはずなのですが、私の環境では駄目だったため再起動しました)。

$ sudo shutdown -r now

NVIDIA Container Toolkitのインストール

NVIDIAのnvidia-container-toolkitパッケージをインストールします。Quickstartの手順をスクリプト化したので、以下の通り実行すればOKです。

$ curl -s https://raw.githubusercontent.com/karaage0703/ubuntu-setup/master/install-nvidia-container-toolkit.sh | /bin/bash

 続いてDockerを起動するため、以下コマンド実行すると…

$ docker run --gpus all --rm nvidia/cuda nvidia-smi
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449: container init caused \"process_linux.go:432: running prestart hook 0 caused \\\"error running hook: exit status 1, stdout: , stderr: nvidia-container-cli: requirement error: unsatisfied condition: cuda>=11.0, please update your driver to a newer version, or use an earlier cuda container\\\\n\\\"\"": unknown.

 cudaがどうこう言われてダメでした…NVIDIAのドライバが古いのでしょうか…

 とりあえず、TensorFlow公式のDockerイメージで試してみます。以下コマンドでDockerを動かします。

$ docker run --gpus all -it --rm --name tensorflow-gpu -p 8888:8888 tensorflow/tensorflow:latest-gpu-py3-jupyter

 実行すると勝手にイメージのダウンロードが始まり、ダウンロードが完了するとコンテナが起動します。起動すると画面に token=xxxxxxxxxxxxxx という形でtokenが表示されます。

 続いて、ブラウザで以下のアドレスにアクセスしましょう。tokenの後は、先ほど表示されたtokenを入力します。

http://127.0.0.1:8888/?token=xxxxxxxxxxxxxx

 Jupyter Notebookにアクセスできました。

jupyter_notebook.png

 以下コマンド実行して、上図のようにGPUが表示されたらOKです。

from tensorflow.python.client import device_lib
device_lib.list_local_devices()

 何か動かしてみたい人は、tensorflow-tutorialというディレクトリの中に、色々なサンプルが入っているのでMNISTあたりを動かしてみると良いと思います。nvidia-smiを起動すれば、メモリが消費されてちゃんとGPUが動いていることが確認できます。

+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.95.01    Driver Version: 440.95.01    CUDA Version: 10.2     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Quadro P600         Off  | 00000000:01:00.0 Off |                  N/A |
| N/A   55C    P0    N/A /  N/A |   3874MiB /  4040MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

NVIDIA-Docker

 気を取り直して、NVIDIA-Dockerを試してみます。最新のNVIDIA-Docker2は、公式サイトのREADMEをもとに、セットアップスクリプト作成しました。以下コマンドでインストールできます。

$ curl -s https://raw.githubusercontent.com/karaage0703/ubuntu-setup/master/install-nvidia-docker.sh | /bin/bash
$ sudo pkill -SIGHUP dockerd

 以下のnvidia-dockerコマンドで、同様に動かせます。

$ nvidia-docker run -it --rm --name tensorflow-gpu -p 8888:8888 tensorflow/tensorflow:latest-gpu-py3-jupyter

NVIDIAの提供しているNGCイメージ

 NVIDAの提供しているNGC の TensorFlow イメージをが良いという話を聞いたので試してみました。

 tensorflow-release-notesをみて、NVIDIAドライバのバージョンが対応しているイメージを探します(Driver Requirementsのところに書かれています)。私がインストールしている NVIDIAのドライバ440.95.01の場合だと、20.03が対応していたので、以下の通り実行してみます。

$ docker run --gpus all --rm nvcr.io/nvidia/tensorflow:20.03-tf1-py3

 一瞬起動画面は出るのですが、Dockerにログインできず…他のバージョンもいくつか試してみましたがダメでした・・・残念ながら諦めました。原因はわかりませんでした。NVIDIAのドライバの関係でしょうか…?

黒画になってしまった場合

 とりあえずリカバリーモードでログインするのが良いです。起動時に「ESC」連打で入れます。

 「ESC」でブート選択画面になるPCの場合は、Continue boot(ブートを続ける)選択をした直後に「ESC」を1回押すと入れたりします。

 rootでCUI画面に入ったら、以下でドライバを削除すると黒画から脱出できたりします。

$ sudo apt --purge autoremove nvidia*

 どうしてもダメなら、素直に再インストールすれば良いと思います。

まとめ

 DockerでディープラーニングのGPU学習環境構築する方法を書きました。色々ハマってしまったので無駄に長くなってしまいました。

 Dockerは、数年前から「便利そうだから使ってみよう!」 → 「やっぱり自分には早かった」を繰り返しているような気がしますが、使いこなせれば、CUDAとTensorFlowのバージョン違いに悩まされなくなったり、色々な環境で素早く試したりができたりするので、なんとか使いこなしていきたいなと思います。

関連ページ

TensorFlowでGPU学習させるためにCUDA周りではまったときの対処法

Docker入門して機械学習環境構築

参考リンク

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

ドライを使ってECSインスタンス上で実行されているDockerコンテナを管理・監視する方法

このチュートリアルでは、Dryを使用してECSインスタンス上で実行されているDockerコンテナ、イメージ、ネットワークを管理・監視する方法を学びます。

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

必要条件

  • 新しく作成したECSインスタンスをUbuntu 16.04でインストールしました。
  • インスタンスに静的IPアドレス192.168.43.192が設定されています。
  • インスタンスにrootパスワードを設定します。

手順

DryでDockerコンテナを管理・監視するには、以下の手順に従います。

Alibaba Cloud ECSインスタンスの起動

まず、Alibaba Cloud ECS Consoleにログオンします。次に、オペレーティングシステムとしてUbuntu 16.04を使用し、少なくとも2GBのRAMを搭載した新しいECSインスタンスを作成します。最後に、ECSインスタンスに接続し、rootユーザーとしてログオンします。

Ubuntu 16.04インスタンスにログオンしたら、以下のコマンドを実行して、ベースシステムを最新の利用可能なパッケージで更新します。

apt-get update -y

Dockerのインストール

次のステップに進む前に、インスタンスにDocker CEDocker composeをインストールする必要があります。デフォルトでは、Ubuntu 16.04のデフォルトリポジトリにはDockerの最新バージョンはありません。そのため、そのためのPPAを追加する必要があります。これは以下のコマンドを実行することで行うことができます。

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"

次に、以下のコマンドを実行してリポジトリを更新し、Docker CEとDocker composeをインストールします。

apt-get update -y
apt-get install docker-ce docker-compose -y

インストールが完了したら、以下のコマンドでDockerサービスの状態を確認することができます。

systemctl status docker

出力は以下のようになります。

● docker.service - Docker Application Container Engine
   Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
   Active: active (running) since Thu 2018-11-15 20:25:06 IST; 56s ago
     Docs: https://docs.docker.com
 Main PID: 16125 (dockerd)
   CGroup: /system.slice/docker.service
           └─16125 /usr/bin/dockerd -H unix://

Nov 15 20:25:04 Node1 dockerd[16125]: time="2018-11-15T20:25:04.988356579+05:30" level=warning msg="Your kernel does not support swap memory li
Nov 15 20:25:04 Node1 dockerd[16125]: time="2018-11-15T20:25:04.989716941+05:30" level=warning msg="Your kernel does not support cgroup rt peri
Nov 15 20:25:04 Node1 dockerd[16125]: time="2018-11-15T20:25:04.991123520+05:30" level=warning msg="Your kernel does not support cgroup rt runt
Nov 15 20:25:05 Node1 dockerd[16125]: time="2018-11-15T20:25:05.000582570+05:30" level=info msg="Loading containers: start."
Nov 15 20:25:06 Node1 dockerd[16125]: time="2018-11-15T20:25:06.049283689+05:30" level=info msg="Default bridge (docker0) is assigned with an I
Nov 15 20:25:06 Node1 dockerd[16125]: time="2018-11-15T20:25:06.278993600+05:30" level=info msg="Loading containers: done."
Nov 15 20:25:06 Node1 dockerd[16125]: time="2018-11-15T20:25:06.353529803+05:30" level=info msg="Docker daemon" commit=4d60db4 graphdriver(s)=o
Nov 15 20:25:06 Node1 dockerd[16125]: time="2018-11-15T20:25:06.361600332+05:30" level=info msg="Daemon has completed initialization"
Nov 15 20:25:06 Node1 systemd[1]: Started Docker Application Container Engine.
Nov 15 20:25:06 Node1 dockerd[16125]: time="2018-11-15T20:25:06.527874596+05:30" level=info msg="API listen on /var/run/docker.sock"

Docker ComposeでWordpressとPhpMyAdminをインストールする

また、DryをテストするためにいくつかのDockerコンテナをセットアップする必要があります。ここでは、Docker composeを使ってWordpressとPhpMyAdminのコンテナをセットアップします。まず、コンテナのデータを保存するディレクトリと、コンテナを実行するためのdocker-compose.ymlを作成します。

mkdir wordpress

次に、wordpressとPhpMyAdminコンテナをセットアップするためのdocker-compose.ymlを作成します。

nano wordpress/docker-compose.yml

以下の行を追加します。

wordpress:
  image: wordpress
  links:
    - wordpress_db:mysql
  ports:
    - 8080:80
wordpress_db:
  image: mariadb
  environment:
    MYSQL_ROOT_PASSWORD: password
phpmyadmin:
  image: corbinu/docker-phpmyadmin
  links:
    - wordpress_db:mysql
  ports:
    - 8181:80
  environment:
    MYSQL_USERNAME: root
    MYSQL_ROOT_PASSWORD: password

保存してファイルを閉じます。ここで、以下のコマンドを実行してWordpressとPhpMyAdminのイメージをダウンロードし、バックグラウンドで両方のコンテナを実行します。

docker-compose up -d

セットアップが完了すると、Wordpressコンテナはポート8080で、PhpMyAdminコンテナはポート8181で待機しています。

Wordpressコンテナにアクセスする

ウェブブラウザを開き、アドレス http://192.168.43.192:8080 を入力します。Wordpressのインストールページにリダイレクトされます。

image.png

言語を選択し、「続行」ボタンをクリックしてください。次のページが表示されるはずです。

image.png

Sitename、adminユーザー名、パスワードを入力します。そして、Wordpressのインストールボタンをクリックします。インストールが完了すると、以下のようなページが表示されます。

image.png

ここで、管理者用のユーザー名とパスワードを入力します。そして、ログオンボタンをクリックします。すると、以下のページにWordpressのダッシュボードが表示されます。

image.png

PhpMyAdminコンテナにアクセスする

ウェブブラウザを開き、アドレスを http://192.168.43.192:8181 と入力してください。次のページにリダイレクトされます。

image.png

ここで、ルートユーザー名とパスワードを入力します。そして、Goボタンをクリックします。すると以下のページにPhpMyAdminのダッシュボードが表示されます。

image.png

Dryのインストール

これで両方のコンテナが設定され、実行されています。次に、Dryをインスタンスにインストールする必要があります。以下のコマンドでDryの最新バージョンをダウンロードできます。

wget https://github.com/moncho/dry/releases/download/v0.9-beta.7/dry-linux-amd64

ダウンロードが完了したら、ダウンロードしたバイナリファイルを /usr/local/bin/ ディレクトリにコピーします。

cp dry-linux-amd64 /usr/local/bin/dry

次に、ドライバイナリファイルに許可を与えます。

chmod 755 /usr/local/bin/dry

では、以下のコマンドを実行してDry版を確認します。

dry -v

以下のように出力されます。

dry version 0.9-beta.7, build dfb8223a

Dryの作業

ここで、ターミナルウィンドウから dry コマンドを実行するだけで dry ユーティリティが起動します。

dry

これにより、docker デーモンと実行中のコンテナに関するすべての有用な情報が読み込まれたプロンプトが表示されます。

image.png

さて、上/下矢印キーを使用してPhpMyAdminコンテナを選択し、Enterキーを押します。次のページにコンテナに関する情報が表示されているはずです。

image.png

ここでは、上下矢印キーを使ってコンテナの再起動、停止、削除、キルを行うことができます。

ESC キーを押してメインダッシュボードに戻ります。次に、3を押して、以下のようにネットワークセクションにアクセスします。

image.png

ここでは、コンテナのネットワーク IP アドレスと MAC アドレスが表示されます。ESC キーをもう一度押して、メインダッシュボードに戻ります。2 を押して、以下のように画像セクションにアクセスします。

image.png

ここでは、実行中のコンテナの画像を見ることができます。また、画像を削除したり、画像の履歴を表示したりすることもできます。

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

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

npm run でコマンドが実行できない[Windows Docker]

環境

  • Windows10
  • Docker Toolbox
$ docker -v
Docker version 18.09.0, build 4d60db472b

やりたいこと

$ docker-compose run --rm /bin/bash
$ npm i --no-bin-links
$ npm run eslint

みたいなコマンドを使いたい。

エラー

sh: 1: eslint: not found

こんな感じで怒られる。

原因

node_modules/.bin にコマンドのリンクが置かれていないため。
Mac では自動で作成されていたため、Windows ではシンボリックリンクがはれない問題 が原因なのかもしれない。

解決法

node_modules を一度全て削除し、docker を介さずに npm i を実行すると node_modules/.bin が作成される。

> npm i
> docker-compose run --rm /bin/bash
$ npm run eslint

とおった。

おまけ

http://minatooe.hatenablog.jp/entry/2017/12/15/234418

あとは、Win は管理者権限なら symlink を作れるようになるらしいので、vagrant を動かすコマンドプロンプトを管理者権限で起動すると--no-bin-links をつけなくても大丈夫になるらしい。

とあったのでやってみたができなかった…。

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

DockerでRailsチュートリアルのローカル開発環境構築 - RSpec導入 & CircleCIでHerokuデプロイ-

はじめに

前回の記事
DockerでRailsチュートリアルのローカル開発環境構築(Rails 6 + PostgreSQL + Webpack) - Qiita

個人開発アプリ
mdClip <オンラインmarkdownエディタ>

前回の記事に続いて、Railsチュートリアルのローカル開発環境構築を行っていきます。

  • Railsチュートリアル最新版(2020.8.6現在)に対応のRails 6

  • Dockerを使用し、開発環境の再現が可能

  • なるべくローカル環境にインストールしない

Docker環境で操作する場合はターミナルのコマンドを適宜

$ docker-compose run app ...

もしくは

$ docker-compose exec app ...

で置き換えてください。

Rspec導入

minitestでも問題ないです
後述のCircleCIでもminitestを走らせる事もできました。

Gemfile

必要に応じて以下のgemを追加
(不要ならminitest関連のgemを削除する)

Gemfile

  # Test enviroment: Rspec
  gem 'rspec-rails'
  gem 'spring-commands-rspec'
  gem 'guard'
  gem 'guard-rspec', require: false

  # Test enviroment: Fake date generator
  gem 'factory_bot_rails'
  gem 'faker'
  gem 'forgery_ja'

bundle install

Gemfileを編集したのでdocker-compose buildが必要です

$ docker-compose build

初期ファイル生成

$ rails g rspec:install

レポートフォーマット

.rspec

--require spec_helper
--format documentation

Guard初期化

$ bundle exec guard init

spring boot対応

$ bundle exec spring binstub --all

Guardの自動テスト時にもspringが有効になるように
Guardfile

$ guard :rspec, cmd: "bundle exec spring rspec" do

CircleCI設定

事前準備

ここでは説明しませんが事前に以下の手順が必要だと思います

  • GitHub & CircleCI & Herokuのアカウント登録
  • SSH接続設定(GitHub - CircleCI)
  • CircleCIへのproject登録および環境変数定義(Heroku APIキー, app名)

設定概要

  • git push -> 自動test (RSpec) -> 自動デプロイ(Heroku)
  • Orbを使うとconfig.ymlの内容を簡略化できる(キャッシュ利用のための記述が不要)
  • Orbを使うためにversion: 2.1指定
  • Docker imageのRuby versionはRailsチュートリアルに合わせて2.6.3
  • Node.jsが必要なので-nodeのついたimageを指定

メモ: Node.js バリアントの Docker イメージ (-node で終わるタグ) に対しては、Node.js の LTS リリースがプリインストールされています。 独自に特定のバージョンの Node.js/NPM を使用する場合は、.circleci/config.yml 内の run ステップで設定できます。 Ruby イメージと共に特定のバージョンの Node.js をインストールする例については、以下を参照してください。

公式サンプルを踏襲しています

公式do - Ruby
Language Guide: Ruby - CircleCI

公式doc - Heroku Deploy
デプロイの構成 - CircleCI

現時点で最新のHeroku-orbは1.2.0ですがバグがあるようで
pull requestされています

deploy-via-git bash script error · Issue #13 · CircleCI-Public/heroku-orb

config.yml

.circleci/config.yml

version: 2.1

orbs:
  ruby: circleci/ruby@1.0
  node: circleci/node@2
  heroku: circleci/heroku@1.1.0

# setupでまとめる
commands:
  setup:
    steps:
      - checkout
      - ruby/install-deps
      - node/install-packages:
          pkg-manager: yarn
          cache-key: "yarn.lock"

jobs:
  build:
    docker:
      - image: circleci/ruby:2.6.3-node
    steps:
      - setup
  test:
    docker:
      - image: circleci/ruby:2.6.3-node
      - image: circleci/postgres:11.6-alpine
        environment:
          POSTGRES_USER: postgres
          POSTGRES_DB: myapp_test
          POSTGRES_PASSWORD: ""
    environment:
      BUNDLE_JOBS: "4"
      BUNDLE_RETRY: "3"
      PGHOST: 127.0.0.1
      PGUSER: postgres
      PGPASSWORD: ""
      RAILS_ENV: test
    steps:
      - setup
      - run:
          name: Wait for DB
          command: dockerize -wait tcp://localhost:5432 -timeout 1m
      - run:
          name: Database setup
          command: bundle exec rails db:schema:load --trace
      - run:
          name: Rspec
          command: bundle exec rspec

  deploy:
    executor: heroku/default
    steps:
      - checkout
      - heroku/install
      - heroku/deploy-via-git:
          maintenance-mode: true
      - run:
          name: DB migrate
          command: heroku run rails db:migrate --app $HEROKU_APP_NAME

workflows:
  version: 2
  test_and_deploy:
    jobs:
      - build
      - test:
          requires:
            - build
      - deploy:
          requires:
            - build
            - test
          filters:
            branches:
              only: master

動作確認

HTMLを書き換える

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  def hello
    render html: "Bye, world!"
  end
end

変更をgit pushして、CircleCIのpipelineがsuccessに変われば
ブラウザから見た内容が上記を反映するはずです

簡単なテスト

仮のrequest_specを作成

rails g rspec:request test

spec/requests/tests_spec.rb

require 'rails_helper'

RSpec.describe "Tests", type: :request do
  describe "GET /" do
    it "Bye, world!が表示されること" do
      get root_path
      expect(response.body).to include "Bye, world!"
    end
  end
end

CircleCI上でも上記テストがpassするはずです

Troubleshoot

CircleCIのtestが以下のエラーで失敗する

rails aborted!
PG::ConnectionBad: could not translate host name "db" to address: Name or service not known

database.ymlの記述が原因です

test環境ではdefaultを引き継いでhost: dbが適応されているはずです

config/database.yml
以下のように書き換えて環境変数がある場合はそちらを優先するようにしました
(ymlのなかでもerbが使えるという学びでした)

test:
  <<: *default
  host: <%= ENV['PGHOST'] || 'db' %>
  database: myapp_test

ERROR IN CONFIG FILE:

インデント、フォーマットの間違いが多いと思います

最後に

  • 意地でローカル環境をきれいに保つことに注力した結果、デプロイやdb:migrateを自動化することで、Heroku CLIすらインストールすることを回避しましたが、素直にHeroku CLIくらいは入れておいた方が今後のエラー解決に役立つ気もします。
  • 難易度は上がりますが、ローカル環境でDocker, CICDを取り入れてのRailsチュートリアル、学べることも多いと思いますので腰を据えて取り組むことのできる方はぜひトライしてみてください。
  • 今後も未知のエラーに遭遇することが予想されますが、おおよそココまでが大変なところかとおもっていますので、この記事がお役に立てれば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む