20201118のdockerに関する記事は16件です。

ansibleを使用してnginxやDockerを単純インストール

事前準備

事前にAnsibleをインストールしておく、ssh-keygen -t rsaでキーを作成してキーでログインできるようにする。

共通設定

接続などの共通設定をいかに示す

inventory.yml
web:
  hosts:
    hostname
  vars:
    domain: helloworld.com
    ansible_user: username
    ansible_ssh_private_key_file: ~/.ssh/id_rsa
    ansible_sudo_pass: test_password

nginxをインストールする場合

aptコマンドを使用して単純にインストール

nginx.yml
- hosts: web
  become: yes
  tasks:
  - name: "install nginx"
    apt:
      name: ['nginx']
      state: latest

実行結果メモ

$ ansible-playbook -i inventory.yml nginx.yaml 

PLAY [web] ********************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************
ok: [hostname]

TASK [install nginx] **********************************************************************************************************************************************
changed: [hostname]

PLAY RECAP ********************************************************************************************************************************************************
hostname     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

nginxサーバが動いていることの単純な動作確認

$ curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

dockerの単純インストール

aptを使用して単純にインストールするだけの動作

docker.yaml
- hosts: web
  become: yes
  tasks:
  - name: "install docker.io"
    apt:
      name: ['docker.io']
      state: latest

実行結果

$ ansible-playbook -i inventory.yml docker.yaml 

PLAY [web] ********************************************************************************************************************************************************

TASK [Gathering Facts] ********************************************************************************************************************************************
ok: [hostname]

TASK [install docker.io] ******************************************************************************************************************************************
changed: [hostname]

PLAY RECAP ********************************************************************************************************************************************************
hostname     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

dockerが動いていることの確認

$ sudo docker ps
[sudo] username のパスワード: 
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【docker-compose】volumesの名無し・名ありボリュームの使い方。バインドマウント

個人メモです。

dockerやdocker-composeで指定するボリュームの使い方について。

docker-compose.ymlにある2つのvolumesの違い

docker-compose.ymlの①外側のvolumesと②servicesの中のvolumesには違いがある。

docker-compose.ymlの例
version: "3.7"

volumes:
  todo-mysql-data:

services:
  mysql:
    image: mysql:5.7
    volumes:
      - todo-mysql-data:/var/lib/mysql

①外側のvolumes

versionと同じ階層にあるvolumesは指定した名前のボリュームを用意している。

これを名ありボリュームという。

volumes:
  todo-mysql-data:

名ありボリュームの特徴(メリット)

  • 複数のコンテナでボリュームを共有できる。
  • コンテナを削除しても消えない(コンテナに依存しない)


②servicesの中のvolumes

各サービスの中のvolumesをバインドマウントと呼び、ボリュームとは区別される。

コンテナ内のディレクトリとホスト側のディレクトリをマウント(共有化)する処理を表す。

services:
  mysql:
    image: mysql:5.7
    volumes:
      - todo-mysql-data:/var/lib/mysql

上記例では、ボリュームtodo-mysql-dataをコンテナ内の/var/lib/mysqlにマウントしている。

これで、/var/lib/mysqlのデータをボリュームに同期できる。


バインドマウント(bind mount)の書き方

バインドマウントには記述方法がいくつかある。

項目 バインドマウント 内容
名ありボリューム datavolume:/var/lib/mysql 指定したボリュームを、コンテナ内の指定ディレクトリにマウントする
名無しボリューム /var/lib/data コンテナ内のディレクトリのみ指定。ハッシュ値のボリュームが割り当てられる。(コンテナ削除で消える)
ルートディレクトリを共有(相対パス) .:app コンテナ内の指定したディレクトリをホスト側の実行中ディレクトリにマウントする。
絶対パスで指定 /opt/data:/var/lib/mysql コンテナ内の指定したディレクトリをホスト側の指定したディレクトリにマウントする。

・ルートディレクトリを共有

.:appのような記述は頻繁に目にする。

これをすることで、コンテナ内のデータをホスト側で再現できる。(これがないとホスト側でデータが見れない)

・名ありボリュームと名ありボリュームの主な用途

項目 名ありボリューム 名無しボリューム
主な用途 ・(1)複数コンテナでボリュームを共有する(例:db)・(2)ホスト側への同期から除外する(例:node_module) 他のコンテナと共有する必要はないが残しておきたいデータ(例:log)
コンテナ削除 残る(コンテナに依存しない) 消える
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerでyarnを入れたはずなのに「ERROR: There are no scenarios; must have at least one」と怒られた時の対処法

背景

Dockerでyarnを入れたはずでしたが、いざ以下コマンドを叩いてみると怒られた

Dockerfileの中身

FROM ruby:2.5
RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \
    nodejs \
    postgresql-client \
    yarn
WORKDIR /kosare
COPY Gemfile Gemfile.lock /kosare/
RUN bundle install

yarnコマンドでエラー発生

root@5847e387581e:/kosare# yarn -v
ERROR: There are no scenarios; must have at least one.

解決策(一時的な解決策)

基本的には参考に記載のURLと同じことをすれば解決します。
私の場合はすでにrootで入っていたので、sudoと記載している部分はなくして順番に実行したら解決しました。

古いyarnを削除

sudo apt remove cmdtest
sudo apt remove yarn

最新を取得

curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -

最新を取得

echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list

update

apt-get update 

再インストール

apt-get install yarn

バージョン確認

yarn -v

解決策(根本的な解決策)

上記のやり方だと、dockerで再度bundle installし直した時に再度同じ事象が発生する。
Dockerfileでbuildした際に解決したいため、以下の2行をdockerfileに追記する。

RUN curl https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list

Dockerfile(最終形)

FROM ruby:2.5
RUN curl https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \
    nodejs \
    postgresql-client \
    yarn
WORKDIR /kosare
COPY Gemfile Gemfile.lock /kosare/
RUN bundle install

これでbuildしなおせば、yarnがちゃんと使えるはず。

参考

https://k-koh.hatenablog.com/entry/2020/04/02/143017
https://github.com/yarnpkg/yarn/issues/7329
https://qiita.com/MasatoraAtarashi/items/3f0317cd648ff63fa92c

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

Raspberry Pi4(Ubuntu server20.04)でDockerを動かす勘所

初めに

 ここに書いたのは、あくまでも2020年11月28日現在の話。Raspberry Pi上のDocker環境は激しく変わる。

 Raspberry Pi OSの64bitはまだβ版。しかし64bitしかサポートしないアプリが増えているのでUbuntuを使う。

dockerは公式の最新を使う

 ディストリビューションからインストールされるバージョンは大抵古いので、Docker公式のレポジトリを登録して使う。

 https://docs.docker.com/engine/install/ubuntu/

$ sudo apt-get update
$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo apt-key fingerprint 0EBFCD88
$ sudo add-apt-repository \
   "deb [arch=arm64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io

docker-compseを入れる

 docker-compseは、公式からARM版バイナリが公開されていません。自力でコンパイル pip3でインストール。

$ sudo apt-get install libffi-dev libssl-dev
$ sudo apt-get install python3 python3-pip python3-dev
$ sudo pip3 install docker-compose
  • Python3はデフォルトでインストールされているかも

MySQL

  • NG(イメージがダウンロード出来ない)
$ docker pull mysql
  • OK
$ docker pull mysql/mysql-server

docker-compose.ymlで image:mysqlと書いてある部分は、mysql/mysql-serverに置き換える(挙動はあまりかわらない)

  • 両者の違いは前者はDocker公式(debian base)で、後者がOracle公式(Oracle Linux base)みたい。

phpmyadmin

  • 動かなっかった AMD64版を動かそうとしていたみたい。
$ docker run phpmyadmin/phpmyadmin

exec user process caused "exec format error" dockerエラーがでてコケた。

  • 動いた
$ docker run arm64v8/phpmyadmin

jwilder/nginx-proxy

 これも動かない。
 Dockerfileを見ると同梱するツールがamd64版をハードコードされていた。一緒に入れているツールのarm64版をコンパイルする必要がありそうなので取りあえずパス。

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

新卒がGoと楽天APIで宿探しBOT作ってみた

概要

4回目の投稿です。
以前、@yagi_engさんがスピーカーを務めたLINEBOTの勉強会に参加してきたので、復習がてら作成記事を書きます。
今回はGoで下記のように自分の位置情報を送信すると、周辺のホテル情報を返すLINEBOTを作成しました。
image.png

機能としては大きく2つです。

  • 位置情報以外の情報(画像やテキスト)を送信すると、「位置情報を送信してください。」と定型文を返す。
  • 位置情報を送信すると、周辺のホテル情報を最大10件返す。

各種ツール

  • go 1.14
  • VS Code 1.51.1
  • Docker 19.03.13
  • ngrok 2.3.35
  • github.com/line/line-bot-sdk-go v7.6.0+incompatible
  • 楽天トラベル施設検索API (version:2017-04-26)

構成

ローカルで立ちあげたサーバをngrokを使って外部公開し、LINF Platformに登録する形をとっています
周辺のホテル情報の検索には楽天トラベル施設検索APIを利用しています。
image.png

ツールの準備をする

LINE Developersに登録する

実装に入る前にまずは、LINEが提供するMassaging APIを利用するために下記の三つを行い、APIを利用するためのChannel secret及びChannel access tokenを取得する必要があります。取得にはLINEのアカウントが必要になります。

楽天APIに登録する

楽天APIの利用にはアプリIDが必要になります。
Rakuten Developersより、アプリIDの発行を行うことができます。
こちらも利用には楽天会員のアカウントが必要になります。

line-bot-sdkを取得する

実装にはline-bod-sdk-goを利用するため、go get します。

go get github.com/line/line-bot-sdk-go/linebot

環境構築

DockerでGoの開発環境を構築する
こちらの記事を参考にDockerでコンテナを作り、8080ポートを割り当ててます。

CONTAINER ID     IMAGE        COMMAND  CREATED      STATUS         PORTS                   NAMES
e56630e11723     linebot_app  "bash"   2 days ago   Up 2 seconds   0.0.0.0:8080->8080/tcp  linebot_app_1

定型文の応答

ローカルホストの立ち上げ

まずはmain関数でローカルホストを立ち上げます。

func main() {
    http.HandleFunc("/callback", callback)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

これでlocalhost:8080/callbackにアクセスすると、callback関数が実行されるようになります。

次にcallback関数の実装です。
https://github.com/line/line-bot-sdk-goの手順に沿って実装していきます。
実装は下記のようになってます。

(hotelInfoBack()は記事後半で説明します。)

func callback(w http.ResponseWriter, r *http.Request) {
    //チャネル作成時に取得したChannel secret及びChannel access tokenを引数に渡す
    bot, err := linebot.New(config.SECRET, config.TOKEN)
    if err != nil {
        log.Fatal(err)
    }
    //http.Requestを*linebot.Eventにパースする。
    events, err := bot.ParseRequest(r)
    if err != nil {
        if err == linebot.ErrInvalidSignature {
            w.WriteHeader(400) //Bad Request
        } else {
            w.WriteHeader(500) //Internal Server Error
        }
        return
    }

    for _, event := range events {
        //リクエストのイベントがメッセージの受信かどうか
        if event.Type == linebot.EventTypeMessage {
            //受信したメッセージの種類による分岐
            switch event.Message.(type) {
            case *linebot.LocationMessage: //位置情報を受信した場合
                hotelInfoBack(bot, event)
            default: //位置情報以外を受信した場合
                _, err = bot.ReplyMessage(event.ReplyToken, linebot.NewTextMessage(backMsg)).Do()
                //bakcMsg = "位置情報を送信してください。"
                if err != nil {
                    log.Print(err)
                }
            }
        }
    }
}

WebhookURLの登録

定型文返答の実装まで終わったら、作成したチャネルのMessageing APIタブからWebhookURLの登録を行います。
image.png

ngrokを使って、外部からローカルのサーバにアクセスするためのURLを発行します。(ngrokの使い方はこちら)
発行したhttps://......ngrok.io/callback入力し、updateをクリックすれば、登録は完了です。
image.png

起動

作成したチャネルのMessageing APIタブのQRコードを読み取り、友達追加します。

image.png

go runでローカルのサーバを立ち上げてから、メッセ―ジを送信すると定型文が返って来るようになりました....が余計なメッセージも返って来ています。
image.png

自動応答機能をオフにする

上記の問題は、MassaginAPIタブのAuto-reply messagesの設定を変更することで解決できます。
画面右側のeditをクリックして、応答メッセージをオフにすれば、余計なメッセージが返ってくることはなくなります。
image.png

image.png

ホテル情報の応答

応答のための処理

hotelInfoBack()を実装していきます。

func hotelInfoBack(bot *linebot.Client, e *linebot.Event) {
    msg := e.Message.(*linebot.LocationMessage)

    //受信した位置情報から、緯度経度を取得する
    lat := strconv.FormatFloat(msg.Latitude, 'f', 2, 64)
    lng := strconv.FormatFloat(msg.Longitude, 'f', 2, 64)

    //ホテル情報を取得する
    replyMsg, couldGetInfo := getHotelInfo(lat, lng)
    //取得に失敗した場合は、定型文(エラーが発生しました。)を返す。
    if !couldGetInfo {
        _, err := bot.ReplyMessage(e.ReplyToken, linebot.NewTextMessage(errorMsg)).Do()
        if err != nil {
            log.Print(err)
        }
    }

    //応答するカルーセルテンプレートを作成する
    res := linebot.NewTemplateMessage(
        "ホテル一覧",
        linebot.NewCarouselTemplate(replyMsg...).WithImageOptions("rectangle", "cover"),
    )
    //応答を返す
    _, err := bot.ReplyMessage(e.ReplyToken, res).Do()
    if err != nil {
        log.Print(err)
    }
}

受信した位置情報に含まれる緯度経度を引数にgetHotelInfo()を実行し、周辺のホテル情報を取得しています。
応答にはMessaging APIに用意されているカルーセルテンプレートを使います。(詳しくはこちら)

ホテル情報を取得する

楽天APIの利用

ホテル情報の検索には楽天トラベル施設検索APIを利用します。
今回は下記のパラメータをリクエストURLにセットして検索を行います。

https://app.rakuten.co.jp/services/api/Travel/SimpleHotelSearch/20170426?[parameter]=[value]…
入力パラメータ名
format(レスポンス形式) json
latitude(緯度) 送信された位置情報の緯度
longitude(経度) 送信された位置情報の経度
serchRadius(検索範囲 : km max = 3) 1
datumType(緯度経度の表示形式) 1 : 世界測地系
applicationID 発行したアプリID

尚、今回利用する出力パラメータは以下のようになります。

出力パラメータ名
HotelSpecial(施設特色)
HotelName (施設名称)
HotelThumbnailURL (施設画像サムネイルURL)
HotelInformationURL(施設情報ページURL)

パースする構造体の作成

今回は取得したjsonを構造体にparseしています。
APIテストフォームより、適当なjsonを取得し、json整形ツールに入れてから、JSON-to-Goを使うことでパースする構造体のコードを取得することができます。
image.png

利用する出力パラメータのみを残した下記の構造体を使います。

type response struct {
    Hotels []struct {
        Hotel []struct {
            HotelBasicInfo struct {
                HotelName           string `json:"hotelName"`
                HotelInformationURL string `json:"hotelInformationUrl"`
                HotelSpecial        string `json:"hotelSpecial"`
                HotelThumbnailURL   string `json:"hotelThumbnailUrl"`
            } `json:"hotelBasicInfo,omitempty"`
        } `json:"hotel"`
    } `json:"hotels"`
}

ホテル情報取得の実装

getHotelInfo()の実装です。

func getHotelInfo(lat, lng string) ([]*linebot.CarouselColumn, bool) {
    url := fmt.Sprintf(apiURL, lat, lng, config.API_ID)
    r, err := http.Get(url)
    if err != nil {
        return nil, false
    }
    defer r.Body.Close()
    body, err := ioutil.ReadAll(r.Body)
    if err != nil {
        return nil, false
    }

    var res response
    //構造体にパースする
    if err = json.Unmarshal(body, &res); err != nil {
        return nil, false
    }

    var ccs []*linebot.CarouselColumn

    //カルーセルカラムの作成
    for index, hotel := range res.Hotels {
        if index == 10 {
            break
        }
        cc := linebot.NewCarouselColumn(
            hotel.Hotel[0].HotelBasicInfo.HotelThumbnailURL,
            cutOutCharacters(hotel.Hotel[0].HotelBasicInfo.HotelName, 40),
            cutOutCharacters(hotel.Hotel[0].HotelBasicInfo.HotelSpecial, 60),
            linebot.NewURIAction("楽天トラベルで開く", hotel.Hotel[0].HotelBasicInfo.HotelInformationURL),
        ).WithImageOptions("#FFFFFF")
        ccs = append(ccs, cc)

    }
    return ccs, true
}


引数で受け取った緯度経度を使い、APIをたたいて取得したjsonを構造体にパースしています。

image.png

構造体スライスを取得したら、それをもとにfor文を回して、カルーセルカラムを作っていきます。
応答で返すカルーセルテンプレートはカルーセルカラムの配列をフィールドとして持っています。(詳しくはこちら)
今回はカルーセルカラムにAPIから取得した、ホテル名、ホテルサムネイル画像、ホテル特色をセットしています。
また、linebot.NewURIAction()で楽天トラベルのホテルページへアクセスするactionを作成し、カルーセルカラムにセットしています。

尚、応答で返せるカルーセルカラムは最大10件となっています。
また、カルーセルカラムに設定する一部フィールドには文字数の制限があるため、文字を切り出す処理を書いています。

//cutOutCharacters 先頭から指定文字数だけを切りだす("abcde",3) → "abc"
func cutOutCharacters(s string, count int) string {
    if utf8.RuneCountInString(s) > count {
        return string([]rune(s)[:count])
    }
    return s
}

参考

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

【Docker】コンテナ内からホストにアクセスする方法。http://host.docker.internal:

コンテナの中からポートにアクセスすることができる。
WEBページの内容を表示する$curl URLコマンドで確認する。

接続方法には、(1)コンテナのポートを指定する方法と、(2)ホストのポートを指定する方法がある。

アクセス手順

1) 起動中のコンテナ内に入る

docker exec -it [コンテナ名] bash

これでコンテナ内のbashにアクセスできる。コンテナによってはbashではなくshの場合もある。

2) curlでhttpをリクエストする

▼コンテナのポートに直接アクセスする場合
curl http://[コンテナ名]:[コンテナ側のポート]

▼ホスト側のポートにアクセスする場合
curl http://host.docker.internal:[ホスト側のポート]

実例

起動中のコンテナを確認
$ docker ps
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS              PORTS                                            NAMES
d4ae7996f53c        django_web                  "python manage.py ru…"   10 hours ago        Up 10 hours         0.0.0.0:8100->8000/tcp                           django_web_1

0.0.0.0:8100->8000/tcpこれが重要!

「ホスト側のポート番号 -> コンテナ内のポート番号」

「0.0.0.0」はlocalhostではなく、全てのポートからのアクセスを表す。

なので、「0.0.0.0:8100 -> 8000」は全ての8100へのアクセスをコンテナ内の8000番ポートにマッピングするという意味になる。


コンテナ内に入る
$ docker exec -it django_web_1 bash
root@d4ae7996f53c:/code#

コンテナ名「django_web_1」のbashを起動。


コンテナのポートに直接アクセスする場合

root@d4ae7996f53c:/code# curl http://django_web_1:8000

http://コンテナ名:コンテナ側のポート番号、これでコンテナ指定したポートにアクセスできる。



間違えてホスト側のポートを指定するとエラーになる。

エラー例
root@d4ae7996f53c:/code# curl http://django_web_1:8100
curl: (7) Failed to connect to django_web_1 port 8100: Connection refused


ホスト側のポートにアクセスする場合

ホスト側のポートにアクセスする場合はhost.docker.internal:ホスト側のポート番号を使う。

root@d4ae7996f53c:/code# curl http://host.docker.internal:8100

host.docker.internalはdocker側で用意してあるDNS。ホスト側のlocalhostに該当する。

これは、コンテナの外側から
curl http://localhost:8100を実行するのと同じ。


コンテナから出る
root@d4ae7996f53c:/code# exit
$

以上。

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

【docker-compose】env_fileとenvironmentの違い。環境変数適用の優先順位について

個人用メモです。

env_fileとenvironmentはどちらもdocker-compose.ymlでrun時に環境変数を指定する

  • run(コンテナ作成)時のみ適用される。
  • build(イメージの作成)では使われない
    • build時に環境変数を指定したい場合は、build -> argsを使う。


env_fileとenvironmentの違い

・環境変数の読み込み方法と設定方法が違う

env_fileは環境変数が記載されたファイルを読み込む

environmentはdocker-compose.ymlに直接変数を記述する。

env_fileの例
env_file: 
  - .env
  - .env.prd
  - .env.local.aws
  - ./common.env
  - ./apps/web.env
environmentの例
environment:
  - NODE_ENV=development
  - PORT=80
  - MIGRATE=true
  - USER=${USER}
  - AWS_REGION=ap-northeast-1


・優先度が違う

それぞれで同じ環境変数を指定している場合、env_fileよりもenvironmentの設定の方が優先される。

env_fileで複数のファイル指定や、environmentで複数重複する変数の指定がある場合は、最後の方が優先される。

ホストに環境変数が設定されている場合は、その値が優先される。

・優先順位:
(1)ホスト > (2)environment > (3)env_file > (4)DockerfileのENV

ホストの環境変数が最優先なため、もしホストの環境変数が適用されてしまう場合は、docker側の環境変数名の変更が必要。


env_file

env_fileで指定するファイルパスはdocker-composeを実行したディレクトリが基準となる。

▼ファイルの指定方法

  1. ファイルが一つの場合 env_file: .env
  2. ファイルが複数の場合(1つでも可)
複数の場合
env_file:
  - .env
  - .env.prd
  - .env.local.aws
  - ./common.env
  - ./apps/web.env
1つの場合
env_file:
  - .env

▼ファイル名は複数の付け方がある

ファイル名 内容
.env デフォルトのファイル名
.env.local.aws 頭に .env がつく
common.env 後ろに .envがつく
./apps/web.env 下の階層のファイル
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

TensorFlowの動作確認環境をDockerで構築する

やりたいこと

TensorFlowのDockerイメージをダウンロード
https://www.tensorflow.org/install/docker?hl=ja
して、コンテナを起動し、tensorflowの動作を確認したい。

前提

  • 任意のホストにDockerがインストール済であること。
  • Dockerコマンドが使えること。

Dockerのインストール手順は
https://qiita.com/kenichiro-yamato/items/7e3cb21613784a27409d

事前確認

バージョン

[root@docker ~]# docker -v
Docker version 19.03.7, build 7141c199a2

稼働中のコンテナ

[root@docker ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

docker pull でイメージを取得する

docker pull tensorflow/tensorflow

結果

[root@docker ~]# docker pull tensorflow/tensorflow
Using default tag: latest
latest: Pulling from tensorflow/tensorflow
171857c49d0f: Pull complete
419640447d26: Pull complete
61e52f862619: Pull complete
40085aa86d3c: Pull complete
b827fdfa00c7: Pull complete
134f84527676: Pull complete
e1f30e7788ed: Pull complete
a13925316d82: Pull complete
5decca4d86ff: Pull complete
70c56a3cd1fa: Pull complete
Digest: sha256:c57fb9628d80872ece8640a22bd0153b2cc8d62d21d79f4d99c3b237a728b62e
Status: Downloaded newer image for tensorflow/tensorflow:latest
docker.io/tensorflow/tensorflow:latest

イメージが取得できたことを確認

[root@docker ~]# docker images
REPOSITORY                             TAG                 IMAGE ID            CREATED             SIZE
tensorflow/tensorflow                  latest              623195db36df        7 weeks ago         1.46GB

docker run でコンテナを起動する

メモリ指定、ポート指定、ホスト指定、共有ディレクトリ指定など、オプション指定は任意で変えてください。

docker run -m 4096m -p 80:80 -d --privileged -h yamato.host -i -t -v /root/share:/share:rw --name tensorflow_container1 tensorflow/tensorflow

コンテナの起動を確認して接続する

[root@docker ~]# docker ps
CONTAINER ID        IMAGE                   COMMAND             CREATED             STATUS              PORTS                NAMES
62f578fc0279        tensorflow/tensorflow   "/bin/bash"         11 seconds ago      Up 10 seconds       0.0.0.0:80->80/tcp   tensorflow_container1

docker exec -it tensorflow_container1 /bin/bash

でtensorflow_container1に接続する。

[root@docker ~]# docker exec -it tensorflow_container1 /bin/bash

________                               _______________
___  __/__________________________________  ____/__  /________      __
__  /  _  _ \_  __ \_  ___/  __ \_  ___/_  /_   __  /_  __ \_ | /| / /
_  /   /  __/  / / /(__  )/ /_/ /  /   _  __/   _  / / /_/ /_ |/ |/ /
/_/    \___//_/ /_//____/ \____//_/    /_/      /_/  \____/____/|__/

接続成功。

初期状態の確認

既にpython3とpipが使える状態になっている。

root@yamato:~# python -V
Python 3.6.9
root@yamato:~# pip

Usage:
  pip <command> [options]

vimが入っていないのでインストールする。

apt-get update

してから

apt-get install vim

で、vimが使えるようになる。

pyファイルを作成して試す

vim test.py

print ("Hello World! I am Kenichiro Yamato")

実行する。

python test.py

Hello World! I am Kenichiro Yamato

が表示されたらOK。

tensorflow のサンプルコードを試す

vi sample.py

import tensorflow as tf
mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)

実行する。

python sample.py

ワーニングやインフォメーションがいくつか出ているが、動作している模様。

2020-11-18 10:00:09.352555: W tensorflow/stream_executor/platform/default/dso_loader.cc:59] Could not load dynamic library 'libcudart.so.10.1'; dlerror: libcudart.so.10.1: cannot open shared object file: No such file or directory
2020-11-18 10:00:09.352579: I tensorflow/stream_executor/cuda/cudart_stub.cc:29] Ignore above cudart dlerror if you do not have a GPU set up on your machine.
2020-11-18 10:00:10.743602: W tensorflow/stream_executor/platform/default/dso_loader.cc:59] Could not load dynamic library 'libcuda.so.1'; dlerror: libcuda.so.1: cannot open shared object file: No such file or directory
2020-11-18 10:00:10.743630: W tensorflow/stream_executor/cuda/cuda_driver.cc:312] failed call to cuInit: UNKNOWN ERROR (303)
2020-11-18 10:00:10.743654: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:156] kernel driver does not appear to be running on this host (yamato.host): /proc/driver/nvidia/version does not exist
2020-11-18 10:00:10.743940: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN)to use the following CPU instructions in performance-critical operations:  AVX2
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2020-11-18 10:00:10.752038: I tensorflow/core/platform/profile_utils/cpu_utils.cc:104] CPU Frequency: 3599995000 Hz
2020-11-18 10:00:10.752747: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x4e64770 initialized for platform Host (this does not guarantee that XLA will be used). Devices:
2020-11-18 10:00:10.752763: I tensorflow/compiler/xla/service/service.cc:176]   StreamExecutor device (0): Host, Default Version
Epoch 1/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.2193 - accuracy: 0.9347
Epoch 2/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0972 - accuracy: 0.9705
Epoch 3/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0676 - accuracy: 0.9789
Epoch 4/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0525 - accuracy: 0.9831
Epoch 5/5
1875/1875 [==============================] - 3s 2ms/step - loss: 0.0423 - accuracy: 0.9862
313/313 [==============================] - 0s 1ms/step - loss: 0.0640 - accuracy: 0.9801
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Linux】DockerでApacheコンテナ起動

はじめに

DockerでApacheコンテナ起動までの流れをメモ

環境情報

  • OS:Redhat 7.7
  • Docker:19.03.6-ce
  • docker-compose:1.27.4
  • apache:2.4.46

docker-compose.yml設定

version: '3'

services:
  apache:
    build: apache
    container_name: apache
    ports:
      - 80:80
    volumes:
      - ./apache/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf

Dockerfile設定

apache

FROM httpd:latest

RUN apt update \
    && apt install -y \
    git \
    gcc \
    make \
    build-essential \
    wget \
    curl \
    llvm \
    xz-utils \
    tk-dev \
    zlib1g-dev \
    libncurses5-dev \
    libbz2-dev \
    libreadline-dev \
    libsqlite3-dev \
    libssl-dev \
    libxml2-dev \
    libxmlsec1-dev \
    liblzma-dev \
    libpq-dev \
    libffi-dev

WORKDIR /usr/local/apache2

apacheコンテナの起動

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

【Linux】Dockerのapacheで自己認証局を作成

はじめに

DockerのApacheで自己認証局を作成する方法をメモ

環境情報

  • OS:Redhat 7.7
  • Docker:19.03.6-ce
  • docker-compose:1.27.4
  • apache:2.4.46

apacheコンテナの起動

apacheコンテナ作成までの流れは下記を参照
【Linux】DockerでApacheコンテナ起動

CA証明書/秘密鍵を作成

apacheコンテナに入り、自己証明書を作成

  • ca_cert.pem:自己署名CA証明書
  • ca_key.pem:自己署名CA証明書の秘密鍵
openssl req -new -x509 -sha256 -newkey rsa:2048 -out ca_cert.pem -keyout ca_key.pem -days 365

CA証明書の秘密鍵パスワード削除

  • ca_key_del_pass.pem:自己署名CA証明書の秘密鍵(パスワード削除)
openssl rsa -in ca_key.pem -out ca_key_del_pass.pem

サブジェクト代替名ファイルを作成

  • subjectAltName.txt:サブジェクト代替名ファイル
subjectAltName = DNS:【DNS】, IP:【IP】

自己証明書の秘密鍵を作成

  • server.key:自己証明書の秘密鍵
openssl genrsa 2048 > server.key

自己証明書の公開鍵を作成

  • server.csr:自己証明書の公開鍵
openssl req -new -sha256 -key server.key > server.csr

自己証明書の公開鍵を自己署名CA証明書と自己署名CA証明書の秘密鍵を使用して署名し、デジタル証明書を作成

  • server.crt:デジタル証明書
openssl x509 -req -sha256 -days 365 -CAcreateserial -in server.csr -CA ca_cert.pem -CAkey ca_key_del_pass.pem -out server.crt -extfile subjectAltName.txt

PEMからDERに変換

ブラウザに取り込む際はDER形式に変換

openssl x509 -inform PEM -outform DER -in cacert.pem -out cacert.cer

docker-compose.yml修正

・作成した自己証明書をvolumesに追加
・portsに「443」を追加

version: '3'

services:
  apache:
    build: apache
    container_name: apache
    ports:
      - 80:80
      - 443:443 <==追加
    volumes:
      - ./apache/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf
      - ./apache/conf/server.crt:/usr/local/apache2/conf/server.crt <==追加
      - ./apache/conf/server.key:/usr/local/apache2/conf/server.key <==追加

各種ファイルの設定

./apache/conf/httpd.conf

・・・
LoadModule ssl_module modules/mod_ssl.so <==追加
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so <==追加

・・・
↓↓↓↓↓↓↓↓↓↓追加↓↓↓↓↓↓↓↓↓↓
Include conf/extra/httpd-ssl.conf
<IfModule ssl_module>
  SSLRandomSeed startup builtin
  SSLRandomSeed connect builtin
</IfModule>
↑↑↑↑↑↑↑↑↑↑追加↑↑↑↑↑↑↑↑↑↑

apacheコンテナの最新化

docker-compose up -d apache

HTTPS接続が可能になっていればOK
https://localhost
※ ドメイン名は適宜変更

参考

Linux Memo/ApacheでSSL自己認証するための簡単な方法(サーバ認証)

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

【Linux】DockerのApacheで自己認証局で署名した自己証明書を作成

はじめに

DockerのApacheで自己認証局を作成し、自己証明書を作成する方法をメモ

環境情報

  • OS:Redhat 7.7
  • Docker:19.03.6-ce
  • docker-compose:1.27.4
  • apache:2.4.46

apacheコンテナの起動

apacheコンテナ作成までの流れは下記を参照
【Linux】DockerでApacheコンテナ起動

docker-compose up -d apache

CA証明書/秘密鍵を作成

apacheコンテナに入り、自己証明書を作成

  • ca_cert.pem:自己署名CA証明書
  • ca_key.pem:自己署名CA証明書の秘密鍵
openssl req -new -x509 -sha256 -newkey rsa:2048 -out ca_cert.pem -keyout ca_key.pem -days 365

CA証明書の秘密鍵パスワード削除

  • ca_key.pem:自己署名CA証明書の秘密鍵
  • ca_key_del_pass.pem:自己署名CA証明書の秘密鍵(パスワード削除)
openssl rsa -in ca_key.pem -out ca_key_del_pass.pem

サブジェクト代替名ファイルを作成

  • subjectAltName.txt:サブジェクト代替名ファイル
subjectAltName = DNS:【DNS】, IP:【IP】

自己証明書の秘密鍵を作成

  • server.key:自己証明書の秘密鍵
openssl genrsa 2048 > server.key

自己証明書の公開鍵を作成

  • server.key:自己証明書の秘密鍵
  • server.csr:自己証明書の公開鍵
openssl req -new -sha256 -key server.key > server.csr

自己証明書の公開鍵を自己署名CA証明書と自己署名CA証明書の秘密鍵を使用して署名し、デジタル証明書を作成

  • server.csr:自己証明書の公開鍵
  • ca_cert.pem:自己署名CA証明書
  • ca_key_del_pass.pem:自己署名CA証明書の秘密鍵(パスワード削除)
  • server.crt:デジタル証明書
openssl x509 -req -sha256 -days 365 -CAcreateserial -in server.csr -CA ca_cert.pem -CAkey ca_key_del_pass.pem -out server.crt -extfile subjectAltName.txt

PEMからDERに変換

ブラウザに取り込む際はDER形式に変換

openssl x509 -inform PEM -outform DER -in cacert.pem -out cacert.cer

docker-compose.yml修正

・作成した自己証明書をvolumesに追加
・portsに「443」を追加

version: '3'

services:
  apache:
    build: apache
    container_name: apache
    ports:
      - 80:80
      - 443:443 <==追加
    volumes:
      - ./apache/conf/httpd.conf:/usr/local/apache2/conf/httpd.conf
      - ./apache/conf/server.crt:/usr/local/apache2/conf/server.crt <==追加
      - ./apache/conf/server.key:/usr/local/apache2/conf/server.key <==追加

各種ファイルの設定

./apache/conf/httpd.conf

・・・
LoadModule ssl_module modules/mod_ssl.so <==追加
LoadModule socache_shmcb_module modules/mod_socache_shmcb.so <==追加

・・・
↓↓↓↓↓↓↓↓↓↓追加↓↓↓↓↓↓↓↓↓↓
Include conf/extra/httpd-ssl.conf
<IfModule ssl_module>
  SSLRandomSeed startup builtin
  SSLRandomSeed connect builtin
</IfModule>
↑↑↑↑↑↑↑↑↑↑追加↑↑↑↑↑↑↑↑↑↑

apacheコンテナの最新化

docker-compose up -d apache

ブラウザにSSL証明書を取り込む

下記に従って「cacert.cer」を取り込む
SSL証明書をインポート

動作確認

HTTPS接続が可能になっていればOK
https://localhost
※ ドメイン名は適宜変更

参考

Linux Memo/ApacheでSSL自己認証するための簡単な方法(サーバ認証)

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

DockerとVisual Studio Codeで.NET 5を体験しよう

はじめに

 .NET 5 が公開されましたが、LTSがついていないしインストールするのはどうしようかなぁと思っている方、DockerとVisual Studio Codeがあれば試せますよ。
 今回はVisualStudio CodeのRemote Development拡張を利用して、Dockerで起動した.NET5のコンテナに接続してプログラムを実行・デバックできるか確認してみます。

テストアプリのビルドと実行

 まずは、テストアプリのコンテナを立ち上げ、ASP.NET MVCプロジェクトを作成して動作確認をしていきます。

.NET5 SDKイメージの起動

 Docker 内部に作成したファイルをホストOS側に保存しておくために、ボリュームマウント用のディレクトリを作り.NET 5のSDKイメージを起動します。また、ASP.NET MVCプロジェクトは標準でhttpが5000番ポートで、httpsが5001番ポートで提供されるのでそれぞれのポートマッピングをしておきます。

mkdir src
docker run -it -p 5000:5000 -p 5001:5001 -v c:¥src:/src mcr.microsoft.com/dotnet/sdk:5.0

ASP.NET MVCプロジェクトの作成と実行

コンテナに接続できたら、先ほどマウントした/srcディレクトリに移動して、新しいMVCプロジェクトを作成します。

cd /src
mkdir WebSite1
cd WebSite1/
dotnet new mvc
The template "ASP.NET Core Web App (Model-View-Controller)" was created successfully.
This template contains technologies from parties other than Microsoft, see https://aka.ms/aspnetcore/5.0-third-party-notices for details.

Processing post-creation actions...
Running 'dotnet restore' on /src/WebSite1/WebSite1.csproj...
  Determining projects to restore...
  Restored /src/WebSite1/WebSite1.csproj (in 67 ms).
Restore succeeded.

 dotnet runでプログラムを実行すると、次のようなエラ〜メッセージが表示されlocalhost:5000がIPV6でバインドできないよ、と言われてしまいます。

root@cc0ff91bfc60:/src/WebSite1# dotnet run                          
Building...
warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
      Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.
warn: Microsoft.AspNetCore.Server.Kestrel[0]
      Unable to bind to https://localhost:5001 on the IPv6 loopback interface: 'Cannot assign requested address'.
warn: Microsoft.AspNetCore.Server.Kestrel[0]
      Unable to bind to http://localhost:5000 on the IPv6 loopback interface: 'Cannot assign requested address'.

 --urls パラメーターで http://0.0.0.0:5000もしくはワイルドカードを使ってhttp://*:5000を指定して実行すると無事起動できます。

root@cc0ff91bfc60:/src/WebSite1# dotnet run --urls http://*:5000
Building...
warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
      Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.
info: Microsoft.Hosting.Lifetime[0]
      Now listening on: http://0.0.0.0:5000
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: /src/WebSite1

 Webブラウザーでアクセスすると、表示できることが確認できます。
image.png

ホストPCのVisualStudio Codeで確認

 前項で作成したDocker内のインスタンスにVisualStudio Codeで接続し、作成したプロジェクトの内容を確認してデバック機能が利用できるかを確認していきます。

VisualStudio Codeの拡張機能のインストール

 VisualStudio Code の Remote Development拡張をインストールします。
image.png

コンテナへのアタッチ

 コマンドパレットからRemote-Containers: Attach to Running Container...を実行して稼働中のコンテナに接続することができます。
image.png
 VisualStudio Codeで/src/WebSite1ディレクトリを開くと、コンテナ内のプロジェクトが表示されます。
image.png

デバックの実行

 コマンドパレットから.NET: Generate Assets for Build and Debugを実行してデバックに必要なファイル(lanunch.jsonとtasks.json)をプロジェクトに追加します。
image.png
 デバック用のファイルを追加後にF5もしくはCtrl+Shift+Dでデバックを開始すると、ビルド後にWebサイトが起動しデバック用のWebブラウザーが起動します。その後はローカルで開発している時と同じようにVisualStudio Codeのデバック機能を利用して開発することができます。
image.png
 Index.cshtmlで環境変数を表示してあげると、コンテナ側の.NETが動作していることがわかります。
image.png

まとめ

なんとなく開発環境にはまだ入れたくないなぁと思っている方、結構簡単に試せるのでやってみてください。

参考

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

Traefikを使ってDockerのローカル開発環境をいい感じに管理する

ローカル開発環境でTraefikに名前解決させることで開発環境毎のポート管理等の手間を省く。
以下のような記述をdocker-compose.ymlに追加して名前解決させたいコンテナをそのネットワークに記述する。

networks:
  docker_default:
    external:
      name: docker_default

Traefikとは

Traefik はDockerにも対応している マイクロサービス向けモダンHTTPリバースプロキシ・ロードバランサ
公式ページ

Træfɪk is a modern HTTP reverse proxy and load balancer made to deploy microservices with ease. It supports several backends (Docker, Swarm, Mesos/Marathon, Consul, Etcd, Zookeeper, BoltDB, Rest API, file...) to manage its configuration automatically and dynamically.

Traefikとportainerの導入

まずdockerなど適当な名前のディレクトを作り以下のようにdocker-compose.ymlを書く。
今回はDockerコンテナをGUIで操作し、管理・監視するためのportainerと言うツールも一緒に構築する

version: '3.8'
services:
  p-portainer:
    image: portainer/portainer
    restart: always
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./portainer:/data
  traefik:
    image: traefik
    ports:
      - "80:80"
    restart: always
    labels:
      - "traefik.http.routers.api.rule=Host(`t.localhost`)"
      - "traefik.http.routers.api.service=api@internal"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./traefik/traefik.toml:/etc/traefik/traefik.toml
networks:
  docker_default:
    external:
      name: docker_default

Traefikの設定ファイルは、toml形式の設定ファイルを作成します。
今回は名前解決のルールをコンテナ名のハイフンより前を正規表現で切り取りネーミングさせます。
(コンテナ名が hoge-fuga だった場合 hoge.localhost とネーミングされます。

※windowsマシンの場合

Docker for windows で /var/run/docker.sock をマウントする必要があるので
上記のdocker-compose.ymlと同じ階層に.env作成し以下を記述する

COMPOSE_CONVERT_WINDOWS_PATHS=1

上記のdocker-compose.ymlを書いたディレクトリの直下にtraefik/.traefik.tomlを作成

[api]

[ping]
  entryPoint = "http"

[providers.docker]
  defaultRule = "Host(`{{ trimSuffix \"-\" (regexFind \"(.+?)-\" .Name) }}.localhost`)"
  network = "docker_default"

これを立ち上げれば、p.localhost でportainerの画面、 t.localhost でtraefikの管理画面にアクセスできるようになります。

まとめ

同時に複数のDocker環境を立ち上げるとポート管理や名前解決が手間になりますが、
traefikのようなプロキシツールを使うと手間が省けて便利です。

サンプル

このサンプルでは test.localhost で名前解決されます。

version: '3.8'
services:
  app:
    build:
      context: .
      dockerfile: ./docker/php/Dockerfile
    tty: true
    volumes:
      - .:/code
      - ./docker/php/php.ini:/usr/local/etc/php/php.ini
  test-web:
    image: nginx:latest
    depends_on:
      - app
    networks:
      - default
      - docker_default
    volumes:
      - ./public:/code/public
      - ./docker/nginx/conf.d/local.d/default.conf:/etc/nginx/conf.d/default.conf
    environment:
      - TZ=${TZ}

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

話題の”全集中”で『Dockerの使い方』を、僕の中に眠るバーチャル禰豆子のためにまとめた。

はじめに

Dockerとは、「開発環境を簡単に作れる便利なツール」です。

本格的に野球しようと思っても、場所作るの大変ですよね…。
ベースを用意して、距離測って置いて、バットもボールも観客席も用意して…。
しかし!Dockerを使えば一瞬でPayPayドームが出来上がります!(出来上がりません。)

野球場は無理ですが、システム開発環境であれば可能です。

  • LAMPサーバー
  • Wordpress
  • Rails+DB etc...

瞬時にシステム開発環境を作成し、その環境を複数人に配ることが可能という便利なアプリです。

この記事について

この記事で、コンテナ等の概念は特に触れていません。
以下のような目的で記事を作成しています。

  • 実際にDockerを触れてみて、システム環境が整う感覚を味わえる。
  • 後日思い出すときにすぐに引き出せる。

ネズコーーー!!!!!!
Dockerがんばって使えるようになるぞーーー!!!

実行環境

※インストールまだの方は、上記公式サイトよりお願いします。

参考にさせていただいたサイト

特に一番上のサイトを勉強及び参考にさせていただきました。概念もしっかり記述されているので、この記事の読者の方、是非閲覧されてください。

では、やってみましょう!

Dockerfileからコンテナを作成

CentOS7にPHPとApachをインストールしたコンテナを作成します。

流れ

① Dockerfileを任意の場所に作成(ファイル名:dockerfile)
② 作成したDockefileからイメージを作成。
③ イメージを元にコンテナを作成する。

手順

① まずはdockerfileをPCに作成する。

dockerfile
#DockerHubからcentos7のイメージをもとにする。
FROM centos:centos7

#centos7のイメージの中でApachとphpをインストール
RUN yum -y install httpd php

#Åpachを起動するためのコマンドを実行
CMD ["/usr/sbin/httpd","-DFOREGROUND"]

② 作成したDockerfileを元に、イメージを作成。

オプション等の説明はDocker ドキュメント日本語化プロジェクトを参照。

#内容
docker build -t イメージ名:タグ名 Dockerfileのディレクトリ

#例|イメージ名はlamptest。タグは1.0。カレントディレクリのdockerfileを使用
docker build -t lamptest:1.0 .

上記を実行するとイメージが作成される。
Screen Shot 2020-11-17 at 11.47.03.png

③ 作成したイメージを元にコンテナ起動

#内容
docker run -d -p ポート番号:ポート番号 --name コンテナ名 イメージ名:タグ名

#例|ポート80版を8080版に割り当てる。 
#   コンテナ名はtestserver。
#   イメージとタグは、lamptest:1.0を使用する。
docker run -d -p 8080:80 --name testserver lamptest:1.0

無事にコンテナの完成です。
Screen Shot 2020-11-17 at 11.59.47.png

http://localhost:8080にアクセスすると、以下画面が表示されます。

Screen Shot 2020-11-17 at 15.29.00.png

※補足※ コンテナの操作

#起動
docker start コンテナ名

#停止
docker stop コンテナ名

#コンテナの中に入る
docker exec -i -t コンテナ名 bash

また操作はGUIでも可能です。
Screen Shot 2020-11-17 at 15.19.03.png

dockerfileコマンドの詳細説明

使用頻度の多いものを簡潔に記載しています。
より詳しい説明はDocker ドキュメント日本語化プロジェクトを参照してください。

From

Dockerイメージをベースに作成する。

#内容
FROM イメージ名:タグ名

#例|centosのイメージをベースにする
FROM centos:centos7

Run

FROMで指定したイメージ対してコマンドを実行。

#内容
FROM 実行するコマンド

#例|yumでhttpdのインストール
RUN yum -y install httpd

COPY

Dockerイメージ内(コンテナ内)にコピーしたいファイルを指定。

#内容
FROM イメージ内にコピーしたいファイルのパス コピー先イメージのパス

#例|Dockerfileと同じディレクトリにあるhogeファイルを、/tmpディレクトリにコピー。
COPY hoge.txt /tmp

ADD

URLが指定できる、tarアーカイブ(gzip、bzip2、xz)で圧縮されるファイルを指定すると自動展開される。
それ以外は、COPYコマンドと同じ。

#内容
ADD イメージ内にコピーしたいファイルパスやURL コピー先のイメージパス。

#例|tar.gzファイルを展開しつつ、イメージ格納
ADD hoge.tar.gz /tmp

#例|URL先のファイルを、指定したディレクトリに保存する。
ADD https://zukan.pokemon.co.jp/detail/025 /tmp

RUN

イメージ作成時に、コマンドを実行する。

#内容
RUN コマンド オプション

#例|lsコマンドを-aのオプションを添えて。
RUN ls -a

CMD

コンテナ起動時に、コマンドを実行する。

#内容
CMD [ コマンド , オプション ]

#例|lsコマンドを-aのオプションを添えて。
CMD [ ls , -a ]

ENV

環境変数数に値を入れる。(イコールは省略可能。)

#内容
ENV 環境変数名=環境変数の値
ENV 環境変数名 環境変数の値

#例|環境変数MIZUNOKOKYUにichinokataを挿入
ENV MIZUNOKOKYU=ichinokata

USER

ユーザー実行名の切り替え

#内容
USER ユーザー名

#例|ユーザー名をakiunleashに切り替え
USER akiunleash

docker-composeで複数のコンテナを作成・連携

アプリとデータベースの複数のコンテナを、一つのシステムとして構築が可能です。
RailsとPostgreSQLのコンテナを別々に作成し、一つのシステムとして連携してみましょう。

流れ

① docker-compose.yml等の必要なファイルを作成
② docker-compose runを使用してイメージ及びコンテナの作成
③ Gemfileが更新されるので、docker-compose bulde で再度構築
④ Rails側からPostgreSQLに接続できるようusernameやpasswordを設定変更
⑤ RailsからPostgreSQLのデータベースの作成
⑥ 完成!

手順

以下4つのファイルを準備します。

  • docker-compose.yml
  • dockerfile
  • Gemfile
  • Gemfile.lock
docker-compose.yml
version: '3'
services:
  db:
    image: postgres
    environment:
      - POSTGRES_PASSWORD=password
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
dockerfile
# DockerHubからcentos7のイメージをもとにする。
FROM ruby:2.3.3

# パッケージ管理ソフトのアップデートからの
# build-essential libpq-dev nodejs をインストール
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs

# コンテナ内にmyappディレクトリ作成
RUN mkdir /myapp

# ワークディレクトリに設定
WORKDIR /myapp

# dockerfileと同ディレクトリにあるファイルを、コンテナ内に作成
ADD Gemfile /myapp/Gemfile
ADD Gemfile.lock /myapp/Gemfile.lock

# Gemfileにかかれてるrailsをインストール 
RUN bundle install

# Railsのファイル及びディレクトリをコンテナに作成
ADD . /myapp
Gemfile
source 'https://rubygems.org'
gem 'rails', '5.0.0.1'
Gemfile.lock
#空ファイル

上記ファイルが保存されたディレクトリでコマンド実行

docker-compose run web rails new . --force --database=postgresql

Gemfileが更新されるので、再度Gemをインストールするためコマンド実行

docker-compose build

データーベースと接続するための情報を編集する。

config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: password
  pool: 5

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test

production:
  <<: *default
  database: myapp_production
  username: myapp
  password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %>

アプリを起動してみましょう!

docker-compose up -d

今の状態はデータベースが無いので作成します。

docker-compose run web rake db:create

確認!

http://localhost:3000/にアクセスし以下のページが表示されれば成功です。
Screen Shot 2020-11-18 at 11.12.38.png

コンテナもしっかりと起動されていることが確認できます。
Screen Shot 2020-11-18 at 11.18.04.png

不要なコンテナが含まれている場合は一度ダウンして、再起動すると消えます。

# 一度ダウン
docker-compose down

# 再度アップ
docker-compose up -d

docker-compose.ymlの解説

docker-compose.yml
version: '3'
services:
  db:
    image: postgres
    environment:
      - POSTGRES_PASSWORD=password
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/myapp
    ports:
      - "3000:3000"
    depends_on:
      - db
項目 説明
version docker-composeのバージョン
services コンテナ名(WEBとDBを作成)
image Docker Hubからイメージを使用
environment 環境変数を設定
build 指定したdockerfileを使用する。
command コンテナ作成後に実行するコマンド
volumes ファイルをマウント
ports ポートの指定
depends_on 起動順序

最後に

Dockerとはどういうものかの感覚を掴むための助けになれば幸いです。
内容に誤りがありましたら、ご指摘いただけると助かります。

変更履歴

日付 内容
2020/11/18 初版
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Docker】Volumes(ボリューム)の中身を見る方法。ルート権限付きコンテナを起動する。

Dockerのボリュームの中に入っているフォルダやファイルを確認する方法について。

確認方法

  1. docker volume inspectでvolumeのmountpoint(絶対パス)を確認する。
  2. イメージからルート権限付きのコンテナを起動する。
  3. コンテナ内のターミナルでlsコマンドを使う
volumeのmountpointの確認
#ボリューム一覧を表示
docker volume ls

#mountpointを確認
docker volume inspect [ボリューム名]
ルート権限付きのコンテナを起動し、ボリュームの中身を確認
#ルート権限つきコンテナ起動
$ docker run -it --privileged --pid=host [イメージ名] nsenter -t 1 -m -u -n -i sh

#ボリュームの中身を表示
/ # ls [mountpointの絶対パス]

#対話モード終了
/ # exit

以上の操作で、volumeの中身を確認することができる。


実例による確認手順

イメージの確認
$ docker images
REPOSITORY                                      TAG                 IMAGE ID            CREATED             SIZE
tomcat                                          latest              35064a4fcc93        2 weeks ago         648MB
django_web                                      latest              7f0eff7ebc94        2 weeks ago         937MB
debian                                          latest              1510e8501783        5 weeks ago         114MB
python                                          3                   dfc47c6cee13        6 weeks ago         886MB
postgres                                        latest              817f2d3d51ec        7 weeks ago         314MB
vuecli                                          3                   4040959eab16        2 months ago        338MB
ボリューム一覧の表示
$ docker volume ls
DRIVER              VOLUME NAME
local               0adf7a2b08b8e09f74ffb7799716e48263f012612dc2047da1d7137a75f12b5d
local               vuecli3_vue-cli-node-volume
mountpointの確認
$ docker volume inspect vuecli3_vue-cli-node-volume
[
    {
        "CreatedAt": "2020-09-08T05:35:36Z",
        "Driver": "local",
        "Labels": {
            "com.docker.compose.project": "vuecli3",
            "com.docker.compose.version": "1.26.2",
            "com.docker.compose.volume": "vue-cli-node-volume"
        },
        "Mountpoint": "/var/lib/docker/volumes/vuecli3_vue-cli-node-volume/_data",
        "Name": "vuecli3_vue-cli-node-volume",
        "Options": null,
        "Scope": "local"
    }
]
docker対話モードに入る
$ docker run -it --privileged --pid=host [イメージ名] nsenter -t 1 -m -u -n -i sh
docker対話モード
/ # ls
EFI         boot        dev         home        lib         mnt         proc        run         srv         tmp         var
bin         containers  etc         init        media       opt         root        sbin        sys         usr
volumeの確認
/ # ls /var/lib/docker/volumes/micres_micres-node_modules2/_data
@babel                                       mime-db
@csstools                                    mime-types
@mdi                                         mimic-response
@nicolo-ribaudo                              mini-css-extract-plugin
@npmcli                                      minimalistic-assert
@rails                                       minimalistic-crypto-utils

ルート権限付きコンテナ起動の詳細

最も肝となる、ルート権限付きコンテナの起動コマンドが何をしているか。

>コマンド
$ docker run -it --privileged --pid=host [イメージ名] nsenter -t 1 -m -u -n -i sh`

-it
-t 擬似ターミナル(--tty)
-i 標準出力常時ON (--interactive)

--privileged
特権モード。ホストに対するルート権限が与えられた特別なコンテナを起動。

--pid=host
--pit= コンテナに対するPIDの名前空間を指定。
host コンテナ内でホスト側のPID名前空間を使う。

nsenter
Dockerで作った名前空間に入るためのコマンドラインツール。
「ENTER into Name Spaces」の頭文字の組み合わせ。



▼nsenterのオプション
-t
「--target pid」プロセスを指定する。ここでは1を指定。

-m
「--mount」 マウント名前空間(mount name space)を入力する。名前空間の指定がなければ、PIDで指定したプロセスを使用する。

-u
「-uts」 UTS名前空間を入力する。名前空間の指定がなければ、PIDで指定したプロセスを使用する。

utsはUnix Time Sharing略。

-n
「--net」 ネットワーク名前空間を入力する。名前空間の指定がなければ、PIDで指定したプロセスを使用する。

-i
「--ipc」 IPC名前空間を入力する。名前空間の指定がなければ、PIDで指定したプロセスを使用する。

要は、PID=1の処理でいろんな名前空間を立ち上げるらしい。

Linux nsenterオプション一覧

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

【メモ】DockerでCentOS8の環境をかんたんに作る

Macの環境でLinuxの勉強をしたい場合に、環境を簡単に作る方法のメモ。

環境

  • macOS Catalina バージョン10.15.7
  • Docker version 19.03.13

コマンド

# Dockerイメージをpull
docker pull centos:8
docker images | grep centos

# コンテナを起動
docker run -it -d --name centos8 centos:8
docker ps | grep centos

## コンテナ内に入る
docker exec -it centos8 /bin/bash
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む