20190512のdockerに関する記事は10件です。

だれでもdocker-composeで楽々Django(Python)環境構築(DBなし)

Docker環境作成用のディレクトリ内構成

docker-django -- Dockerfile
              |
              -- requirements.txt
              |
              -- docker-compose.yml
              |
              -- pythonProject(中身空のディレクトリを作成しておく)

それでは、requirements.txtを作成します。こちらは、djangoで使用するパッケージを記述していきます。

requirements.txt

requirements.txt
Django==2.2

Djangoフレームワーク(バージョン2.1.1)を指定しています。DB関係のパッケージをインストールしたい場合こちらで記述します。

Dockerfile

Dockerfile
FROM python:3.7
ENV PYTHONUNBUFFERED 1
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt

docker-compose.yml

docker-compose.yml
version: "3"

services:
  python37:
    build: .
    volumes:
      - ./pythonProject/:/code
    tty: true
    ports:
      - 8000:8000

◆注意点◆
PHPの経験がある人は、環境構築の際に/var/wwwの場所にコードを配置したと思いますが、PythonコードをWebサーバーのドキュメントルート下に置いてしまうと、他人がWebを通して、コードを読めるようになってしまうため、安全性に欠けてしまいます。そのため、今回はcode下に置いています。コードの置き場所参考記事

docker compose up -d

docker-compose.ymlに記述しているすべてのサービスを起動します

コマンド
docker compose up -d

完了したら、コマンド打ってコンテナが作成されているか確認してみましょう。できてたら環境構築終わり

コマンド
$ docker ps -a
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS                                        NAMES
33378ade007f        dockerdjango_python37   "python3"                15 minutes ago      Up 12 minutes       0.0.0.0:8000->8000/tcp                       dockerdjango_python37_1

Djangoで初期画面を表示する

Djangoでいうアプリケーションとプロジェクトの違い
- アプリケーション 処理を行う
- プロジェクト 設定記述・アプリケーションを配下にもつ

$ docker-compose exec python37 bash

Djangoプロジェクト作成

コンテナ内に入れましたら、プロジェクトを作成します。

コマンド
root@bc8400473a8a:/code# django-admin startproject djangoProject .

最後に.(ドットをつけるのは、階層を深くしたくないからそうしています)(今回プロジェクト名 = djangoProject)

Djangoアプリ作成

プロジェクトと同階層でアプリを作成します。(アプリ名 = sampleApp)

コマンド
root@bc8400473a8a:/code# python manage.py startapp sampleApp

Django初期画面表示

Djangoでは、公開するホストを指定する必要があります。djangoProject下にあるsettings.pyを編集します。

settings.py
ALLOWED_HOSTS = ['192.168.99.100']

今回は、Dockerを使用していて、192.168.99.100(デフォルトのものを指定)

それではdjangoの開発用のサーバを起動します。

root@bc8400473a8a:/code# python manage.py runserver 0.0.0.0:8000

http://192.168.99.100:8000/
にアクセスできて、画面が表示されれば完了です。おめでとうございます!

Screenshot_1.png

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

だれでもdocker-composeで楽々Django(Python)環境構築(DBなし)#1

Docker環境作成用のディレクトリ内構成

pythonProject

docker-django -- Dockerfile
              |
              -- requirements.txt
              |
              -- docker-compose.yml

docker-django(環境用)とpythonProjectは同階層です。
それでは、requirements.txtを作成します。こちらは、djangoで使用するパッケージを記述していきます。

requirements.txt

requirements.txt
Django==2.1.1

Djangoフレームワーク(バージョン2.1.1)を指定しています。DB関係のパッケージをインストールしたい場合こちらで記述します。

Dockerfile

Dockerfile
FROM python:3.7
ENV PYTHONUNBUFFERED 1
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt

docker-compose.yml

docker-compose.yml
version: "3"

services:
  python37:
    build: .
    volumes:
      - ../pythonProject/:/code
    tty: true
    ports:
      - 8000:8000

docker compose up -d

docker-compose.ymlに記述しているすべてのサービスを起動します
:コマンド
docker compose up -d

完了したら、コマンド打ってコンテナが作成されているか確認してみましょう。できてたら環境構築終わり

コマンド
docker ps -a
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS                                        NAMES
33378ade007f        dockerdjango_python37   "python3"                15 minutes ago      Up 12 minutes       0.0.0.0:8000->8000/tcp                       dockerdjango_python37_1

Djangoで初期画面を表示する

Djangoでいうアプリケーションとプロジェクトの違い
- アプリケーション 処理を行う
- プロジェクト 設定記述・アプリケーションを配下にもつ

docker-compose exec python37 bash

Djangoプロジェクト作成

コンテナ内に入れましたら、プロジェクトを作成します。

コマンド
django-admin startproject djangoProject .

最後に.(ドットをつけるのは、階層を深くしたくないからそうしています)(今回プロジェクト名 = djangoProject)

Djangoアプリ作成

アプリを作成します。

:コマンド(アプリ名 = sampleApp)
python manage.py startapp sampleApp

Django初期画面表示

Djangoでは、公開するホストを指定する必要があります。djangoProject下にあるsettings.pyを編集します。

settings.py
ALLOWED_HOSTS = ['192.168.99.100']

今回は、Dockerを使用していて、192.168.99.100(デフォルトのものを指定)

それではdjangoの開発用のサーバを起動します。

python manage.py runserver 0.0.0.0:8000

http://192.168.99.100:8000/
にアクセスできて、画面が表示されれば完了です。おめでとうございます!

Screenshot_1.png

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

nuxt docker

Dockerfile
FROM node:latest # version指定 docker inspect => "NODE_VERSION=11.14.0"
EXPOSE 7000      # port 7000 を開ける
ENV HOST 0.0.0.0 # container に どのipaddressでも接続できる<=これ無しだと、接続できない。ipaddressが違う?
docker-compose.yml
version: "3"  
services:
  web:
    build: .      #<= ./ でも同じ
    volumes:
      - ".:/app"  #<= ./:/app でも同じ <= host:container
    ports:
      - 7000:3000 #<= ホストで7000を開くとコンテナの3000につながる。バインディング。Dockerfileと揃える
    container_name: "nuxt-sandbox"
    tty: true     #<= 入力を受け付ける

上の二つを同じフォルダに置いて、

docker-compose up -d
// -d ありだと、バックグラウンド起動、無しだと、ターミナル上で起動します
docker exec -itnuxt-sandbox bash
yarn create nuxt-app <project-name>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

docker-compose.ymlとDockerコンテナのPHPで環境変数を使用する

はじめに

これは個人的な備忘録になります。

docker-compose.ymlで環境変数を使用する

docker-compose.ymlがあるディレクトリ直下に、「.env」 を用意する。そのファイル内で定義した値を使用できる。

例えば、以下のように定義をした場合

.env
# REDIS関係
REDIS_PORT=6379
REDIS_PASSWORD=password

docker-compose.ymlでは、以下のように使用できる

docker-compose.yml
  redis:
    image: redis:alpine3.9
    command: redis-server --requirepass ${REDIS_PASSWORD}
    ports:
      - "${REDIS_PORT}:${REDIS_PORT}"

dockerコンテナで環境変数を使用する

dockerコンテナ内で環境変数を使用する場合は、docker-compose.ymlで定義する。

環境変数を1個〜2個指定する場合は、「environment」で定義をする。
以下のファイルでは、DATABASE_HOST/REDIS_HOSTを定義している。

docker-compose.yml
  app:
    build: ./app
    env_file: .env
    environment:
      DATABASE_HOST: db
      REDIS_HOST: redis
    depends_on:
      - db
      - redis
    volumes:
      - ./data/html:/var/www/html

また、複数指定したい場合は、「env_file」として、環境変数を記載しているファイルを指定する。

この時に、「.env」ファイルを使い回すことで、環境変数を「.env」ファイルに集約ができる。

PHPのコンテナでPHP.iniで注意点

PHP.iniでは、環境変数を使う、使わない、または有効にする変数の優先順位設定があります。

それが「variables_order」になります。デフォルトでは、「GPCS」となっていますので、環境変数は使えないです。

Dockerの環境変数が読み込めなくてハマりました。
「EGPCS」にすると、環境変数を優先して使ってくれます。

php.ini
; This directive determines which super global arrays are registered when PHP
; starts up. G,P,C,E & S are abbreviations for the following respective super
; globals: GET, POST, COOKIE, ENV and SERVER. There is a performance penalty
; paid for the registration of these arrays and because ENV is not as commonly
; used as the others, ENV is not recommended on productions servers. You
; can still get access to the environment variables through getenv() should you
; need to.
; Default Value: "EGPCS"
; Development Value: "GPCS"
; Production Value: "GPCS";
; http://php.net/variables-order
variables_order = "GPCS"

これでPHPのコード内で環境変数を使えるようになります。

$redis = new Redis();
$redis->connect($_ENV['REDIS_HOST'], $_ENV['REDIS_PORT']);

コードだけではなくて、PHP.iniの中でも環境変数は使えるようです。

php.ini
memory_limit=${PHP_MEMORY_LIMIT}

参考文献

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

Node.jsで作ったスクレイピングアプリをDockerコンテナで起動してみた

やりたかったこと

  • サーバーレス環境でスクレイピングアプリを動かしたかった
  • Knative試したかったのでコンテナ化する必要があった

nodejsでスクレイピングするアプリをサクッと作る

まずは好きなところにディレクトリ切って下記コマンドを叩く
npm init
出てくる質問は全てEnter連打した
次にスクレイピングに必要な selenium-webdriver をインストール
https://www.npmjs.com/package/selenium-webdriver

npm install selenium-webdriver

scrapingするプログラムを書いていきます。今回はgoogle chromeが既にインストールされている前提で話を進めます。

vim example.js

example.js
const { Builder, By, Capabilities } = require('selenium-webdriver');

const capabilities = Capabilities.chrome();
capabilities.set('chromeOptions', {
  args: [
    '--headless',
    '--no-sandbox',
    '--disable-gpu',
    '--window-size=1980,1200',
    // other chrome options
  ],
});

(async function example() {
  console.log('start google scraping');

  const driver = await new Builder().forBrowser('chrome').withCapabilities(capabilities).build();
  try {
    await driver.get('https://www.google.com/?hl=');

    const text = await driver.findElement(By.xpath('/html')).getText();
    console.log(text);
  } finally {
    await driver.quit();
    console.log('finish scraping');
  }
}());


const sleep = time => new Promise((resolve) => {
  setTimeout(() => {
    resolve();
  }, time);
});

puppeteerもサクッと立ち上げるのには良さそうだったけどブラウザがchromium縛りになるのが嫌だったので今回はWebdriver使いました

npm scriptsを定義する

package.json のscriptsに以下のようにstartタスクを追加します

package.json
"scripts": {
    "start": "node ./example.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },

試しにスクレイピングを走らせてみます
npm start

consoleログ

fuga@hoge ~/D/g/scraping-sample> npm start

> scraping-sample@1.0.0 start /Users/a12711/Documents/git-localrepository/scraping-sample
> node ./example.js

start google scraping
Gmail
画像
ログイン
日本
プライバシー規約設定
広告ビジネスGoogleについて
finish scraping

うまくスクレイピングが動いてそうです

Dockerfileを作る

今回はサクッと作りたかったので、seleniumのstandalone-chromeのイメージを元にして、nodejsをインストールするDockerfileを作成しました

Dockerfile
FROM selenium/standalone-chrome:3.141.59 

WORKDIR /usr/src/app

COPY package*.json ./

USER root

RUN curl -SL https://deb.nodesource.com/setup_8.x | bash
RUN apt-get install -y nodejs

RUN npm install

COPY . .

CMD npm start

Docker Build

dockerが入っていない方はdocker desktop等でdocker入れてください

Dockerイメージを作成する
docker build -t sample/robot .

コンテナ起動
docker run sample/robot

consoleログ
fuga@hoge ~/D/g/scraping-sample> docker run sample/robot

> scraping-sample@1.0.0 start /usr/src/app
> node ./example.js

start google scraping
Gmail
画像
ログイン
日本
プライバシー規約設定
広告ビジネスGoogleについて
finish scraping

先程と同様のログが出ています
これでスクレイピングのアプリをDockerコンテナとして動かすことができました

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

Railsの「annotate」gemが最高すぎる件

環境

  • Docker version 18.09.2
  • Ruby 2.4.5
  • Rails 5.0.0

なぜ書いたのか

「あれ、テーブルってどんな構造してたっけ❓」
っていう時がかなりあった。

今まで確認する時は、

  1. DBに入る
  2. コマンドぽちぽち入力
  3. DB抜ける

上記3点のプロセスだったのが、

  1. Modelのrbファイル確認

annotateをインストールするだけでここまで短縮できることに感動したから

導入、実装

1.Gemfileに追記

Gemfile
group :development do 
  gem 'annotate' 
end

※基本的に開発環境でのみ使用するので、development内に書く

2.gemをインストール

ターミナル
$ docker-compose build

3.gemの実行

ターミナル
$ docker-compose exec web bundle exec annotate

これでModelを確認すると、下記のような感じでコメントアウトでテーブルの構造が!すごい!
スクリーンショット 2019-05-12 20.54.35.png

ただこれだとテーブルを作成、更新するたびに実行しなければならないので、
migrationをトリガーに実行するように設定ファイルを生成

ターミナル
docker-compose exec web bundle exec rails g annotate:install

これでmigrationの度にannotateが実行されるように?

おまけ

routeにも適用できるらしいのでやってみた

ターミナル
$ docker-compose exec web bundle exec annotate --routes

スクリーンショット 2019-05-12 21.17.53.png

参考

https://qiita.com/tsuchinoko_run/items/9bcc15e8992cb237e08a
https://www.udemy.com/share/1014LIB0sacllTQ3s=/

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

Docker CEからRootless Dockerへ移行してみる on EC2

概要

現在、EC2上でDocker CEを利用している。先日↓の記事を見かけたので、Rootless Dockerへの移行(といっても、Volumeのみ)を試してみる。
RootlessモードでDockerをより安全にする [DockerCon発表レポート] – nttlabs – Medium

Rootless Docker?

Rootlessモードは,Dockerデーモン及びコンテナを,非rootユーザで実行する技術です.Rootlessモードを用いることにより,万一Dockerに脆弱性や設定ミスがあっても,攻撃者にホストのroot権限を奪取されることを防ぐことが出来ます.

参考: RootlessモードでDockerをより安全にする [DockerCon発表レポート] – nttlabs – Medium

:thinking:Amazon Linuxでいうところのec2-userユーザだけで、Dockerデーモンの起動からdockerコマンドの利用までできるということ。

普通にDockerを起動すると、rootユーザでコンテナを起動する必要があるから、rootを乗っ取られる可能性がある。
よくある一般ユーザをdockerグループに属させて、一般ユーザでdockerコマンドを利用できるようにさせても、Docker自体はrootユーザで起動させているから、rootを乗っ取られる可能性がある。

Rootless Dockerは、一般ユーザだけで完結できるから、rootを取られる可能性が限りなく0に近づくってことですかね。

試した環境

少しOSやDocker CEが古いが...:expressionless:

OS
[ec2-user@localhost ~]$ cat /etc/os-release
NAME="Amazon Linux AMI"
VERSION="2018.03"
ID="amzn"
ID_LIKE="rhel fedora"
VERSION_ID="2018.03"
PRETTY_NAME="Amazon Linux AMI 2018.03"
ANSI_COLOR="0;33"
CPE_NAME="cpe:/o:amazon:linux:2018.03:ga"
HOME_URL="http://aws.amazon.com/amazon-linux-ami/"
DockerCE
[ec2-user@localhost ~]$ docker version
Client:
 Version:           18.06.1-ce
 API version:       1.38
 Go version:        go1.10.3
 Git commit:        e68fc7a215d7133c34aa18e3b72b4a21fd0c6136
 Built:             Mon Mar  4 21:25:23 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          18.06.1-ce
  API version:      1.38 (minimum version 1.12)
  Go version:       go1.10.3
  Git commit:       e68fc7a/18.06.1-ce
  Built:            Mon Mar  4 21:26:49 2019
  OS/Arch:          linux/amd64
  Experimental:     false

移行前のコンテナ環境

まずは、移行を試す環境を作る。
docker volume createでボリュームを作り、centosコンテナにマウントさせて起動する。
起動したコンテナ上で、1GBほどのファイルを作っておく。

[root@localhost ~]# docker volume create test
test
[root@localhost ~]# docker run -itd  -v test:/mnt centos
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
8ba884070f61: Pull complete
Digest: sha256:b5e66c4651870a1ad435cd75922fe2cb943c9e973a9673822d1414824a1d0475
Status: Downloaded newer image for centos:latest
d1256d1226bcd445616f13a0e73bbb322056c9151c7adbc7c7d84011e2afe4eb
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
d1256d1226bc        centos              "/bin/bash"         7 seconds ago       Up 6 seconds                            romantic_bell
[root@localhost ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos              latest              9f38484d220f        8 weeks ago         202MB
[root@localhost ~]# docker volume ls
DRIVER              VOLUME NAME
local               test
[root@localhost ~]# docker exec -it romantic_bell bash
[root@d1256d1226bc /]# cd /mnt
[root@d1256d1226bc mnt]# dd if=/dev/zero of=zerofile bs=1024 count=1000000
1000000+0 records in
1000000+0 records out
1024000000 bytes (1.0 GB) copied, 2.46405 s, 416 MB/s
[root@d1256d1226bc mnt]# ls -lh
total 977M
-rw-r--r-- 1 root root 977M May 12 08:49 zerofile
[root@d1256d1226bc mnt]# exit

移行前準備

Rootless Dockerをインストール(Docker CEを削除)する前に、ホスト側から前項で作成したボリュームを退避させる。
退避前にコンテナも止めておく。
退避したボリュームは、Rootless Dockerを実行するユーザ、グループに予め変更しておく。

[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
d1256d1226bc        centos              "/bin/bash"         7 seconds ago       Up 6 seconds                            romantic_bell
[root@localhost ~]# docker stop romantic_bell
romantic_bell
[root@localhost ~]# cp -rp /var/lib/docker/volumes /tmp/
[root@localhost ~]# chown -R ec2-user:ec2-user /tmp/volumes/
[root@localhost ~]# docker rm romantic_bell
romantic_bell

Docker CEのアンインストール

Rootless Dockerを入れる前に、Docker CEをアンインストールする。
アンインストールをしないと、何故かRootless DockerがDocker CEの/var/run/docker.sock等を使って起動しなかった:innocent:

[root@localhost ~]# yum -y remove docker
Loaded plugins: priorities, update-motd, upgrade-helper
Resolving Dependencies
--> Running transaction check
---> Package docker.x86_64 0:18.06.1ce-8.28.amzn1 will be erased
--> Finished Dependency Resolution

Dependencies Resolved

==============================================================================================================================================
 Package                     Arch                        Version                                     Repository                          Size
==============================================================================================================================================
Removing:
 docker                      x86_64                      18.06.1ce-8.28.amzn1                        @amzn-updates                      150 M

Transaction Summary
==============================================================================================================================================
Remove  1 Package

Installed size: 150 M
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
  Erasing    : docker-18.06.1ce-8.28.amzn1.x86_64                                                                                         1/1
  Verifying  : docker-18.06.1ce-8.28.amzn1.x86_64                                                                                         1/1

Removed:
  docker.x86_64 0:18.06.1ce-8.28.amzn1

Complete!
[root@localhost ~]# 

Rootless Dockerのインストール&実行

インストールといっても、コマンド1つで終わるらしい。:thinking:

[ec2-user@localhost ~]$ curl -fsSL https://get.docker.com/rootless | sh
# Missing system requirements. Please run following commands to
# install the requirements and run this installer again.
# Alternatively iptables checks can be disabled with SKIP_IPTABLES=1

cat <<EOF | sudo sh -x
curl -o /etc/yum.repos.d/vbatts-shadow-utils-newxidmap-epel-7.repo https://copr.fedorainfracloud.org/coprs/vbatts/shadow-utils-newxidmap/repo/epel-7/vbatts-shadow-utils-newxidmap-epel-7.repo
yum install -y shadow-utils46-newxidmap
EOF

パッケージが足りない。:frowning2:

[ec2-user@localhost ~]$ cat <<EOF | sudo sh -x
> curl -o /etc/yum.repos.d/vbatts-shadow-utils-newxidmap-epel-7.repo https://copr.fedorainfracloud.org/coprs/vbatts/shadow-utils-newxidmap/repo/epel-7/vbatts-shadow-utils-newxidmap-epel-7.repo
> yum install -y shadow-utils46-newxidmap
> EOF
~省略~
[ec2-user@localhost ~]$ curl -fsSL https://get.docker.com/rootless | sh
Could not find records for the current user ec2-user from /etc/subuid . Please make sure valid subuid range is set there.
For example:
echo "ec2-user:100000:65536" >> /etc/subuid

/etc/subuid,/etc/subgidがない。
そもそも見た記憶がない。作る。:rolling_eyes:

[root@localhost ~]$ sudo su -
[root@localhost ~]# echo "ec2-user:1000:65536" >> /etc/subuid
[root@localhost ~]# echo "ec2-user:1000:65536" >> /etc/subgid
[root@localhost ~]# exit
[ec2-user@localhost ~]$ curl -fsSL https://get.docker.com/rootless | sh
# systemd not detected, dockerd daemon needs to be started manually

/home/ec2-user/bin/dockerd-rootless.sh --experimental --storage-driver vfs

# Docker binaries are installed in /home/ec2-user/bin
# WARN: dockerd is not in your current PATH or pointing to /home/ec2-user/bin/dockerd
# Make sure the following environment variables are set (or add them to ~/.bashrc):\n
export XDG_RUNTIME_DIR=/tmp/docker-500
export DOCKER_HOST=unix:///tmp/docker-500/docker.sock

言われた通りに、.bashrcに追加する。
また、binディレクトリもできていたので、合わせて追加する。
/tmp/docker-500配下にdocker.sockができるので、嫌な場合はこれらの環境変数を変えておけばよさそう。

[ec2-user@localhost ~]$ echo "export XDG_RUNTIME_DIR=/tmp/docker-500" >> ~/.bashrc
[ec2-user@localhost ~]$ echo "export DOCKER_HOST=unix:///tmp/docker-500/docker.sock" >> ~/.bashrc
[ec2-user@localhost ~]$ echo 'PATH=$PATH:$HOME/bin' >> .bashrc
[ec2-user@localhost ~]$ source .bashrc

インストールが終わったので、言われたとおりにサーバを起動する。
起動し続けておく必要があるので、screenで起動する。デタッチは、デフォルトはCtrl-a押してd

[ec2-user@localhost ~]$ screen
[ec2-user@localhost ~]$ /home/ec2-user/bin/dockerd-rootless.sh --experimental --storage-driver vfs
INFO[2019-05-12T08:08:51.179358654Z] Default bridge (docker0) is assigned with an IP address 172.17.0.0/16. Daemon option --bip can be used to set a preferred IP address
INFO[2019-05-12T08:08:51.330646070Z] Loading containers: done.
INFO[2019-05-12T08:08:51.344736419Z] Docker daemon                                 commit=3998dff graphdriver(s)=vfs version=master-dockerproject-2019-05-11
INFO[2019-05-12T08:08:51.344855472Z] Daemon has completed initialization
INFO[2019-05-12T08:08:51.362135829Z] API listen on /tmp/docker-500/docker.sock
[detached]
[ec2-user@localhost ~]$
[ec2-user@localhost ~]$ docker version
Client:
 Version:           master-dockerproject-2019-05-11
 API version:       1.40
 Go version:        go1.12.5
 Git commit:        53fc2572
 Built:             Sat May 11 23:39:34 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server:
 Engine:
  Version:          master-dockerproject-2019-05-11
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.5
  Git commit:       3998dff
  Built:            Sat May 11 23:46:26 2019
  OS/Arch:          linux/amd64
  Experimental:     true
 containerd:
  Version:          v1.2.6
  GitCommit:        894b81a4b802e4eb2a91d1ce216b8817763c29fb
 runc:
  Version:          1.0.0-rc8
  GitCommit:        425e105d5a03fabd737a126ad93d62a9eeede87f
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

適当なコンテナを起動してみる

dockerコマンドはパスを通したので今までどおり使える。

[ec2-user@localhost ~]$ docker run -d -p 8080:80 nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
743f2d6c1f65: Pull complete
6bfc4ec4420a: Pull complete
688a776db95f: Pull complete
Digest: sha256:23b4dcdf0d34d4a129755fc6f52e1c6e23bb34ea011b315d87e193033bcd1b68
Status: Downloaded newer image for nginx:latest
a26c026eddf0f0d92db01e6cd6984f83904ffc5b4d69dd245a3a88081cdc6db5
[ec2-user@localhost ~]$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
a26c026eddf0        nginx               "nginx -g 'daemon of…"   4 seconds ago       Up 3 seconds        0.0.0.0:8080->80/tcp   xenodochial_khayyam
[ec2-user@localhost ~]$ curl http://localhost:8080
<!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>
[ec2-user@localhost ~]$

Rootless Docker動いた:relaxed:

ボリュームの移行

そもそもvolumesディレクトリはどこにあるのか。:thinking:

[ec2-user@ip-172-31-47-41 ~]$ ll /tmp/docker-500/
total 12
drwx-----T 7 ec2-user ec2-user 4096 May 12 08:58 docker
-rw-r--r-T 1 ec2-user ec2-user    5 May 12 08:58 docker.pid
srw-rw---T 1 ec2-user     1496    0 May 12 08:58 docker.sock
drwx-----T 2 ec2-user ec2-user 4096 May 12 08:08 runc
[ec2-user@ip-172-31-47-41 ~]$ find . -name 'docker'
./.vim/plugged/ultisnips/docker
./.local/share/docker
~省略~
[ec2-user@ip-172-31-47-41 ~]$ ll .local/share/docker/
total 56
drwx------ 2 ec2-user ec2-user 4096 May 12 08:08 builder
drwx------ 4 ec2-user ec2-user 4096 May 12 08:08 buildkit
drwx------ 3 ec2-user ec2-user 4096 May 12 08:08 containerd
drwx------ 4 ec2-user ec2-user 4096 May 12 09:11 containers
-rw------- 1 ec2-user ec2-user   36 May 12 08:08 engine_uuid
drwx------ 3 ec2-user ec2-user 4096 May 12 08:08 image
drwxr-x--- 3 ec2-user ec2-user 4096 May 12 08:08 network
drwx------ 4 ec2-user ec2-user 4096 May 12 08:08 plugins
drwx------ 2 ec2-user ec2-user 4096 May 12 08:58 runtimes
drwx------ 2 ec2-user ec2-user 4096 May 12 08:08 swarm
drwx------ 2 ec2-user ec2-user 4096 May 12 09:11 tmp
drwx------ 2 ec2-user ec2-user 4096 May 12 08:08 trust
drwx------ 3 ec2-user ec2-user 4096 May 12 08:15 vfs
drwx------ 3 ec2-user ec2-user 4096 May 12 09:08 volumes
[ec2-user@ip-172-31-47-41 ~]$

ホームディレクトリの.local/share/docker配下にあった

[ec2-user@ip-172-31-47-41 ~]$ ll .local/share/docker/volumes
total 24
-rw------- 1 ec2-user ec2-user 32768 May 12 09:08 metadata.db

メタデータがあるので、ディレクトリだけ移動
でも移動だけだと認識されないので、同名でdocker volume create

[ec2-user@localhost ~]$ mv /tmp/volumes/test ~/.local/share/docker/volume/
[ec2-user@localhost ~]$ docker volume ls
DRIVER              VOLUME NAME
[ec2-user@localhost ~]$
[ec2-user@localhost ~]$ docker volume create test
test
[ec2-user@localhost ~]$ docker volume ls
DRIVER              VOLUME NAME
local               test

あとは、Docker CEのときと同じようにコンテナを作成する。

[ec2-user@localhost ~]$ docker run -itd  -v test:/mnt centos
Unable to find image 'centos:latest' locally
latest: Pulling from library/centos
8ba884070f61: Pull complete
Digest: sha256:b5e66c4651870a1ad435cd75922fe2cb943c9e973a9673822d1414824a1d0475
Status: Downloaded newer image for centos:latest
cfbadb0e2e67047bf25e23a2ce73835dfb9557e8341e4aead1cf658d69eacf9a
[ec2-user@localhost ~]$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
cfbadb0e2e67        centos              "/bin/bash"         About a minute ago   Up About a minute                       jolly_fermi
[ec2-user@localhost ~]$
[ec2-user@localhost ~]$
[ec2-user@localhost ~]$ docker inspect jolly_fermi | grep volume
                "Type": "volume",
                "Source": "/home/ec2-user/.local/share/docker/volumes/test/_data",
[ec2-user@localhost ~]$ docker exec jolly_fermi /bin/ls /mnt -l
total 1000004
-rw-r--r-- 1 root root 1024000000 May 12 08:49 zerofile
[ec2-user@ip-172-31-47-41 ~]$ docker exec jolly_fermi bash -c "echo 'hello' >> /mnt/hello.txt"
[ec2-user@ip-172-31-47-41 ~]$ cat .local/share/docker/volumes/test/_data/hello.txt
hello
[ec2-user@ip-172-31-47-41 ~]$

どうやらボリュームの移行はちゃんとできたようだ:clap:

[参考]
moby/rootless.md at master · moby/moby
RootlessモードでDockerをより安全にする [DockerCon発表レポート] – nttlabs – Medium

最後に

気が向いたらdocker-composeで作成したものも試しておきたい。

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

【Docker for Windows】コンテナ上のChromiumのウインドウとサウンドをホストOSへ転送してみた

やったこと

Docker for Windows上のコンテナでChromiumを起動させ、ChromiumのウインドウとサウンドをホストOSであるWindows 10へ転送しました。

コンテナ上のChromiumからウインドウ、サウンドをそれぞれ以下の手法で転送しました。

  • ウインドウの転送
      image.png   X Window System(X11)

  • サウンドの転送
      image.png   PulseAudio

概念図

image.png

動作環境

  • Windows 10 Pro version 1803, build 17134.706
  • Docker Desktop version 2.0.0.3 (31259), build: 8858db3
  • Docker Engine version 18.09.2, build 6247962

やり方

1. ホストOS(Windows 10)側での準備

1.1. X11 Server の導入

1.1.1. X11 Server のインストール

  コンテナ上のウインドウを受信するため、Windows 10にX11 Serverをインストールします。
  ここでは、X11 ServerとしてVcXsrvを使用します。インストールに当たり、参考にさせて頂きましたサイトを掲載します。(丸投げのような形で申し訳ございません)

1.1.2. X11 Server の起動

  デスクトップ上の「XLaunch」から、VcXsrvを起動します。(全て[次へ]を選択し、[完了]を押せばOKです)
  タスクトレイにVcXsrvのアイコンが表示されていれば、起動しています。
  image.png

1.2. PulseAudio for Windowsの導入

1.2.1. PulseAudio for Windows のインストール

  PulseAudio on Windowsのダウンロードサイトから「zipfile containing preview binaries」を選択して、zipファイルをダウンロードし、任意に場所へ解凍します。

1.2.2. PulseAudio for Windows の設定

  • 「etc\pulse\default.pa」の編集
42行目 設定
変更前 load-module module-waveout sink_name=output source_name=input
変更後 load-module module-waveout sink_name=output source_name=input record=0
61行目 設定
変更前 #load-module module-native-protocol-tcp
変更後 load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1
  • 「etc\pulse\daemon.conf」の編集
39行目 設定
変更前 ; exit-idle-time = 20
変更後 exit-idle-time = -1

1.2.3. PulseAudio for Windows の起動

  解凍した「pulseaudio-1.1」フォルダと同階層に以下のバッチファイルを配置して、実行します。

pulseaudio.bat
@echo off

cd /d %~dp0

powershell -NoProfile -Command Start-Process -WindowStyle Minimized '.\pulseaudio-1.1\bin\pulseaudio.exe'

  以下のようなコマンドプロンプトが表示されていれば、起動しています。(「Ctrl+C」で停止できます)
  ※Windows Firewallから許可を求められた場合は、許可をしてください。
image.png

2. Dockerイメージの作成

2.1. X11 の環境設定

 Dockerfile内で環境変数 DISPLAYを以下のように設定します。

ENV DISPLAY=host.docker.internal:0.0

2.2. Pulseaudio の環境設定

 Dockerfile内で環境変数 PULSE_SERVERを以下のように設定します。

ENV PULSE_SERVER=tcp:host.docker.internal:4713

 また、ALSAのdefaultサウンドカードとして、PulseAudio(仮想サウンドカード)を登録します。

{ \
echo "pcm.default pulse"; \
echo "ctl.default pulse"; \
} | tee ~chrome/.asoundrc \
&& chown -R chrome:chrome /home/chrome

2.3 Dockerfileサンプル

zenika/alpine-chromeをベースに以下のDockerfileを作成しました。

Dockerfile
# Credit goes to Zenika (https://github.com/Zenika/alpine-chrome/blob/master/Dockerfile) 
FROM alpine:latest

# Installs latest Chromium package.
RUN echo @edge http://nl.alpinelinux.org/alpine/edge/community >> /etc/apk/repositories \
    && echo @edge http://nl.alpinelinux.org/alpine/edge/main >> /etc/apk/repositories \
    && apk add --no-cache \
    chromium@edge \
    harfbuzz@edge \
    nss@edge \
    freetype@edge \
    ttf-freefont@edge \
    mesa-gl \
    pulseaudio \
    pulseaudio-libs \
    alsa-plugins-pulse@edge \
    bash \
    && wget https://noto-website.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip \
    && mkdir -p /usr/share/fonts/NotoSansCJKjp \
    && unzip NotoSansCJKjp-hinted.zip -d /usr/share/fonts/NotoSansCJKjp/ \
    && chmod 644 /usr/share/fonts/NotoSansCJKjp/*.otf \
    && rm NotoSansCJKjp-hinted.zip \
    && fc-cache -fv

# Add user so we don't need --no-sandbox. 
RUN addgroup -S chrome \
    && adduser -S -G chrome chrome \
    && mkdir -p /home/chrome/Downloads \
    && { \
    echo "pcm.default pulse"; \
    echo "ctl.default pulse"; \
    } | tee /home/chrome/.asoundrc \
    && chown -R chrome:chrome /home/chrome

# Run Chrome as non-privileged
USER chrome
WORKDIR /home/chrome

ENV CHROME_BIN=/usr/bin/chromium-browser
ENV CHROME_PATH=/usr/lib/chromium/
ENV DISPLAY=host.docker.internal:0.0
ENV PULSE_SERVER=tcp:host.docker.internal:4713

# Autorun chrome
ENTRYPOINT ["chromium-browser", "--disable-gpu", "--disable-software-rasterizer", "--disable-dev-shm-usage"]

2.4 ビルド

docker build -t speaktech/secure-browser:1.0 .

3. コンテナの実行

 zenika/alpine-chromeの手引きに従い、限られた権限でChromiumのsandobox機能を利用するためにseccompプロファイル(chrome.json)を利用します。

Invoke-WebRequest -Uri https://raw.githubusercontent.com/jfrazelle/dotfiles/master/etc/docker/seccomp/chrome.json -OutFile chrome.json

docker run -it --rm --security-opt seccomp=$(pwd)/chrome.json speaktech/secure-browser:1.0

コンテナを実行すると、Windows 10上でChromiumが起動します。Youtubeなどで音声がWindows 10へ転送されることを確認できれば、完了です。

image.png

4. 最後に、なぜやろうと思ったのか?

 インターネットへのアクセスをコンテナに実行させることで、セキュアなブラウザ環境ができるのでは?と思い、やってみました。
 ブラウザを閉じる度にコンテナごと削除するので、ウイルス感染後の情報漏洩等のリスクが低くなります。
 また、Windows Firewallを利用して、コンテナからの通信をウインドウ/サウンドの転送のみに絞ることで、ホストOSのウイルス感染リスクを軽減できると考えます。

 難点としては、ウインドウとサウンドを非同期に転送している関係上若干音ズレします。(私個人としては、許容範囲内です)
 
 「これで、より安心に、いろいろなサイトを閲覧できる気がします」という意味深な感想で締めさせていただきます。
 最後までご拝読いただきまして、ありがとうございました。

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

GO111MODULE=onなプロジェクトでDockerのビルド時間を短くした工夫

はじめに

Go1.11から採用のGo Modules(vgo)なプロジェクトにて、Dockerのビルドが遅かったのをキャッシュ利用で一応解決できた話。

順を追って

はじめの状態

下記のような構成

.
├── Dockerfile
├── go.mod
├── go.sum
└── main.go
Dockerfile一部抜粋
COPY . ./
RUN CGO_ENABLED=0 GOOS=linux go build -o binary # 遅い!

Goコードの中では大きなOSSプロジェクトライブラリを利用しているので本コードを改修するたびにDockerビルドにて対象パッケージをダウンロードして遅い!

次にvendorをレポジトリに入れてみた

下記のコマンドでパッケージたちをvendorとしてレポジトリに組み込んでみました。

$ go mod vendor
$ tree
.
├── Dockerfile
├── go.mod
├── go.sum
├── main.go
└── vendor
    ├── package1
    ├── package2
Dockerfile一部抜粋
COPY . ./                                                   # ここの通信コストが大きくなってしまった
RUN CGO_ENABLED=0 GOOS=linux go build -mod=vendor -o binary # ここは速くなったけど

これでパッケージを毎回ダウンロードしないのでビルド時間はたしかに短くなった。
しかしレポジトリが巨大になってしまいました。
そして、このプロジェクトではDocker-Machineのリモート接続でDockerを扱っているのでローカルからリモートへの通信コストがvendorのせいでエグいことになってしまいました。
(そもそも.dockerignoreもまともに記載していなかったのでこれはこれで対応。)

解決策 パッケージダウンロードなイメージレイヤを設けてキャッシュ利用

vendorは削除しました。
他言語のプロジェクトと同様な戦略でパッケージに関わる部分を先にダウンロードするイメージレイヤを作ることでキャッシュを活用することにしました。

Dockerfile一部抜粋
ENV GO111MODULE="on"  # Go Modulesを使うと明言する
COPY go.mod go.sum ./ # パッケージ用メタファイルだけコピー
RUN go mod download   # メタファイルに変更がなければキャッシュ利用できる

COPY . ./
RUN CGO_ENABLED=0 GOOS=linux go build -o binary

go.modに修正が入らない限りRUN go mod downloadはキャッシュが利用されるので、一番はじめのビルド時間の遅さは解決できました。
また、新しいパッケージを利用しはじめてそれがgo.modに反映されていなくてもgo buildが代わりにダウンロードするので問題なくイメージがビルドされます。

最後にDockerfileの全体感

Dockerfileの全体としては以下のような感じにしています。
マルチステージングの機能を利用して最終的にできあがるイメージは最小になるよう努めています。

Dockerfile
FROM golang:1.12.5-stretch as builder

WORKDIR /workdir

ENV GO111MODULE="on"
COPY go.mod go.sum ./
RUN go mod download

COPY . ./

RUN CGO_ENABLED=0 GOOS=linux go build -o binary

FROM alpine:3.8

WORKDIR /root/

# Multi stage build function of Docker
COPY --from=builder /workdir/binary .

CMD ["./binary"]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

fishでdockerコマンドの補完を行う

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