20210122のdockerに関する記事は19件です。

【2】Docker-compose + Django の環境で管理画面からアプリのでデータベース管理をする

概要

  • Docker-composoe + Django環境で作業環境を整えます。
  • Djangoは専用の管理画面からデータベースの操作(作成や編集など)が行えます。
    • つまりPHPMyAdminなどが不要!!

環境

  • Docker + Docker-compose が利用できること。
  • Python3.6
  • Django3.1(最新)

前提

手順

アプリケーションの作成

  • アプリケーションの作成
$ docker-compose exec django manage.py sample

コンフィグの修正

  • src/app/settings.pyを編集する
    • INSTALLED_APPS に作成したアプリケーションを追加する
      • sample: フォルダ名
      • SampleConfig: src/app/sample/apps.py に書いてあるclass
src/app/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'sample.apps.SampleConfig',         # 追加
]

モデルの作成

  • src/app/sample/models.pyを編集する
src/app/sample/models.py
from django.db import models


class Test1(models.Model):
    class Meta:
        verbose_name_plural = "テスト1"

    test1_name = models.CharField("テスト名",max_length=25)
    test1_value = models.CharField("テスト値",max_length=25)
    def __str__(self):
        return self.test1_name


class Test2(models.Model):
    class Meta:
        verbose_name_plural = "テスト2"

    test1= models.ForeignKey(Test1, on_delete=models.PROTECT)
    test2_name = models.CharField("テスト名",max_length=25)
    test2_value = models.CharField("テスト値",max_length=25)
    def __str__(self):
        return self.test2_name

管理画面の設定

  • src/app/sample/admin.pyを編集する
from django.contrib import admin

# Register your models here.

from order.models import Test1, Test2
admin.site.register(Test1)
admin.site.register(Test2)

マイグレーション

  • マイグレーションファイルを作成して実行
$ docker-compose exec django ./manage.py makemigrations
$ docker-compose exec django ./manage.py migrate

確認

  • 下記へログインするとモデルで作成したデータベースが操作できる
    • http://<IP>:8000/admin
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【2】Django の管理画面からアプリケーションのデータベース管理をする

概要

  • Docker-composoe + Django環境で作業環境を整えます。
  • Djangoは専用の管理画面からデータベースの操作(作成や編集など)が行えます。
    • つまりPHPMyAdminなどが不要!!

環境

  • Docker + Docker-compose が利用できること。
  • Python3.6
  • Django3.1(最新)

前提

手順

アプリケーションの作成

  • アプリケーションの作成
$ docker-compose exec django manage.py sample

コンフィグの修正

  • src/app/settings.pyを編集する
    • INSTALLED_APPS に作成したアプリケーションを追加する
      • sample: フォルダ名
      • SampleConfig: src/app/sample/apps.py に書いてあるclass
src/app/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'sample.apps.SampleConfig',         # 追加
]

モデルの作成

  • src/app/sample/models.pyを編集する
src/app/sample/models.py
from django.db import models


class Test1(models.Model):
    class Meta:
        verbose_name_plural = "テスト1"

    test1_name = models.CharField("テスト名",max_length=25)
    test1_value = models.CharField("テスト値",max_length=25)
    def __str__(self):
        return self.test1_name


class Test2(models.Model):
    class Meta:
        verbose_name_plural = "テスト2"

    test1= models.ForeignKey(Test1, on_delete=models.PROTECT)
    test2_name = models.CharField("テスト名",max_length=25)
    test2_value = models.CharField("テスト値",max_length=25)
    def __str__(self):
        return self.test2_name

管理画面の設定

  • src/app/sample/admin.pyを編集する
src/app/sample/admin.py
from django.contrib import admin

# Register your models here.

from order.models import Test1, Test2
admin.site.register(Test1)
admin.site.register(Test2)

マイグレーション

  • マイグレーションファイルを作成して実行
$ docker-compose exec django ./manage.py makemigrations
$ docker-compose exec django ./manage.py migrate

確認

  • 下記へログインするとモデルで作成したデータベースが操作できる
    • http://<IP>:8000/admin
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DjangoとSvelteを使ってSPAを作るためのテンプレートの紹介

DjangoとSvelteを使ってSPAを作るためのテンプレートの紹介

github https://github.com/muzin00/django_svelte_starter_on_docker

dockerを使用しての環境構築です。

databaseはpostgresqlです。

環境構築の手順はgithubに乗せてあります。

自分はdjangoもsvelteも学習しだしたばかりなので何か間違いがあったり動かなかったりしたら
すいません。コメントで教えていただけると助かります。

vscodeを使っている人は公式からでているsvelteの拡張機能をインストールすることをおすすめします。いれないとつらいと思います。

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

コンテナでDBを作る【mysql】

悩んだ末に絞り出したコンテナ設定の備忘録です。

条件

下記の設定が記載されたテンプレートを元に必要な機能を追記する
・mysql5.7公式dockerイメージを元に、その他必要な設定をcomposeファイルで行う
・データ用のボリュームを用意しコンテナ起動時にマウント
・Mysqlの環境変数の設定がなければDB名等をダミーで作成するシェルが、コンテナ起動時にDBのボリュームが存在しない場合に実行される

これに加え
・初回コンテナ起動時にテーブル定義〜ダミーデータのインポートまで自動で行えるようにしたい

辿り着いた設定

実際のファイルはここに載せると長くなる為載せないけど、こんなイメージのものを作成

composeファイルでイメージがビルド

下記のディレクトリがマウント
・データ用ディレクトリ
・mysql設定ファイル配置ディレクトリ
・エントリーポイント用ディレクトリ

エントリーポイント用ディレクトリに下記を配置
・init.sh(テンプレート)
・テーブル定義用sqlファイル
・データインポート用シェル(インポートするデータサイズが大きい為シェル内で圧縮されたファイルの解凍等も行っている)

テーブル定義とデータ部分のインポートを分けたので何かエラーがあったときに箇所が明確になる
また、テーブル定義かデータのどちらかを差し替えたい場合も分けて対応できる
あと、データインポート用シェルには必要な処理を色々追記できるというメリットがある
(インポートが終わったらdumpファイルを削除するとか)

若干はまったこと

composeファイルに記載した下記の変数について

MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'

この設定によりcomposeファイルで

    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
      DB_NAME: test
      DB_USER: root

上記のように設定すると、testDBのrootユーザーにはパスワードが存在しないはずなのに、なぜかパスワードが生成された状態でDBが起動する為不思議に思っていたけど、テンプレートのシェルをよく見たら「パスワードが空または定義されていない場合、これを代入」的な処理になっていたので、これが原因とわかった。

dbName="${DB_NAME:-aaa}"
dbUser="${DB_USER:-bbb}"
dbPassword="${DB_PASSWORD:-ccc}"

sql="create database if not exists ${dbName}"
echo "${sql}" | ${cmd} mysql

sql="grant all on ${dbName}.* to ${dbUser}@'%' identified by '${dbPassword}'"
echo "${sql}" | ${cmd} mysql

細かく検証していないけど、デフォルト(localhostからのアクセスのみ受け付ける)rootユーザーのパスワードが無くなるという設定のための専用変数ということはさすがにないはず。

どこかで配布されているテンプレートなんだろうか、、出どころ不明だけど、今回はこれを元に作業している為仕方ない、これに手を加えない手段だと、手っ取り早いのはcomposeファイルでパスワードを設定してしまう方法なのでそれで対応。

もしシェルを改修して良ければ、こんな感じでやるかも

if [DB_PASSWORDが値関係なく(nullでも)定義が存在すれば]; then
    定義されているものを優先(nullでも)
else
    xxxxxxxxを使用する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dockerを使って爆速でGPUを設定する方法

はじめに

機械学習をやろうと思ったら、まずやってくるのが GPUの設定 ですよね。ドライバインストールしてCUDAとcudnnインストールして、、、。これが本当にめんどくさい!そんな方には Dockerを用いた設定をオススメします。マジで爆速です。しかも、PyTorchやTFによって環境を別で設定できますし、使わなくなったらその環境をすぐに削除できます。ひと通りカバーした記事があまりなかったので残しておきます。困っている方の参考になればと思います。

*ミスがありましたら、ぜひご指摘お願いします

手順

1. NVIDIA driver のインストール

2. Docker のインストール

3. NVIDIA container toolkit のインストール


1. NVIDIA Driverのインストール

$ nvidia-smi
$ sudo apt-get --purge remove nvidia-*
$ sudo apt autoremove
$ sudo add-apt-repository ppa:graphics-drivers/ppa
$ ubuntu-drivers devices
$ sudo apt-get install nvidia-driver-450

2. Dockerのインストール

  • aptのindex更新
$ sudo apt-get update
  • 前提ソフトウェアをインストール
$ sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
  • Dockerの公式GPG公開鍵のインストール
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
OK
  • 公開鍵のフィンガープリントを確認
$ sudo apt-key fingerprint 0EBFCD88
pub   rsa4096 2017-02-22 [SCEA]
      9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid           [ unknown] Docker Release (CE deb) <docker@docker.com>
sub   rsa4096 2017-02-22 [S]

*「0EBFCD88」は鍵ID

  • repositoryの追加
$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
$ sudo apt-get update
  • Docker CE のインストール
$ sudo apt-get install -y docker-ce
  • この状態だと、$ sudo docker psのようにsudoを付加しないと実行できないので変更
# dockerグループの情報表示
$ getent group docker

# Dockerグループにユーザ追加
$ sudo gpasswd -a [username] docker

# 権限を付与
$ sudo chgrp docker /var/run/docker.sock

# 追加されているか確認
$ id [username]

# 再起動
$ sudo reboot
  • エラーが消えているか確認
$ docker ps
  • これでエラーが出なかったらOK
$ sudo docker run hello-world

3. NVIDIA container toolkit

  • インストール
$ distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
$ curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
$ curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

$ sudo apt-get update && sudo apt-get install -y nvidia-container-toolkit
$ sudo systemctl restart docker
  • 確認
$ nvidia-container-cli info

4. DockerでGPUを使う

  • イメージをpull
$ docker pull nvidia/cuda:10.0-cudnn7-devel-ubuntu18.04 
  • docker上でNVIDIAドライバが認識されていればOK
$ docker run --gpus all nvidia/cuda:10.0-cudnn7-devel-ubuntu18.04 nvidia-smi
  • イメージを元にコンテナを作成する
  • 以下は、CUDA:10.0、cudnn:7を使用する場合
$ docker run -it -d --gpus all --name gpu_env nvidia/cuda:10.0-cudnn7-devel-ubuntu18.04 bash
$ docker ps
  • コンテナに入る
$ docker exec -it gpu_env bash

5. コンテナで作業

root@cf3868e92ebf:/# nvidia-smi
root@cf3868e92ebf:/# nvcc -V
root@cf3868e92ebf:/# apt-get update
root@cf3868e92ebf:/# apt-get install -y python3 python3-pip
root@cf3868e92ebf:/# pip3 install torch torchvision
root@cf3868e92ebf:/# python3
Python 3.6.9 (default, Oct  8 2020, 12:12:24) 
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 
>>> import torch
>>> print(torch.cuda.is_available())
True
>>> 
  • コンテナを抜ける
root@cf3868e92ebf:/# exit

その他(dockerコマンド)

  • ローカルにあるイメージの一覧表示
$ docker images
  • 起動中のコンテナ表示
$ docker ps
  • コンテナの起動
$ docker start CONTAINER
  • コンテナの停止
$ docker stop CONTAINER
  • 起動中のコンテナに入る
$ docker exec -it CONTAINER bash
  • コンテナの名前変更
$ docker rename OLD_CONTAINER_NAME NEW_ONTAINER_NAME
  • コンテナの削除
$ docker rm CONTAINER

参考文献

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

Docker有償プラン(Pro)の申込方法

はじめに

昨年(2020年)に一部を騒がせたDockerのフリープランでの各種制限の導入ですが、みなさんもイメージをプルする前にDockerにログインしておくなど、以前とは開発体験に変化があったのではないでしょうか?

ここでは、FreeプランからProプランへの移行申込方法についてご紹介します。入力等、画面を見ればあまりに自明だからなのか、Qiitaでも類似した記事を見つけられなかったので、書いてみました。

FreeプランとProプランの違い

移行手続きに入る前に、FreeプランとProプランでできることにどの程度違いがあるのでしょうか? 詳しくは、Pricing & Subscriptionsのページをご覧いただくのが早いのですが、今日(2021/01/22)現在では、こういった違いがあるようです。

Freeプラン(無料)

  • パブリックなリポジトリをいくつでも作成可能
  • プライベートなリポジトリは1つのみ作成可能
  • ロールベースのアクセス制限が可能なユーザ管理
  • 1チーム、3チームメンバーまで登録可能
  • コンテナイメージのプルリクエストは6時間200回まで(未ログインだとIPアドレスごとに6時間で100回まで)
  • 2要素認証の設定可能

Proプラン(7ドル/月, または60ドル/年)

  • Freeプランでの提供内容(上述)プラス
  • プライベートなリポジトリもいくつでも作成可能
  • コンテナイメージのプルリクエスト回数は無制限
  • 2パラレルビルド
  • 1サービスアカウント
  • Slack通知
  • 300イメージ/月まで脆弱性スキャン
  • プレミアムカスタマーサポート(メールベース)

得られる「開発者体験」が毎月7ドル(年払いなら5ドル)に見合うのであれば、Proプランを申し込みましょう!

Proプラン申込手順

自アカウントにログイン、加入中プランを確認

dockerhubにアクセスし、自分のアカウントにログインします。

右上の指紋マークの左側にある自分のIDをクリックし、Billingをクリックすると、現在加入中のプランが表示されます。

Free Repository Plan

上の画面では、現在加入中のプランが Free Repository Plan である旨、表示されています。では、右側にある Change Plan ボタンをクリックします。

アップグレードプランの内容・費用確認

先にご紹介したようなFreeプランとProプランの比較、ならびに費用が表示されていますので、確認の上、Upgrade nowボタンをクリックします。

Change Plan

なお、Learn moreリンクをクリックすると、Pricing & Subscriptionsのページが表示され、FreeとProの他に、Teamプラン、Largeプランについての情報も提供されています。

支払方法の入力

さて、Upgrade nowボタンをクリックすると、Payment Method(支払方法)の入力画面になります。年払い(pay annually)か月払い(pay monthly)を選択の上、氏名、クレジットカード番号、有効期限、CNN、住所(CountryにJapanを指定すると郵便番号入力欄が表示されます)を入力し、Purchase(購入)ボタンをクリックします。

Payment Method

アップグレード完了

Purchaseボタンをクリックすると、現在加入中のプランが改めて表示されます。先ほどはFree Repository Planだったのが、Pro Planに更新されているのがわかります。

Pro Plan

おわりに

さて、Proプランであれば、Slack通知、および脆弱性プランの設定方法が気になるところです。別途、記事を起こして紹介させていただきます。

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

docker-composeの面白い挙動を発見した。

問題

docker-composeで定義されたコンテナ名と別のコンテナのサービス名が同じだと、Dockerネットワーク内での名前解決がコンテナ名でできなくなる

本家には報告ずみです。
https://github.com/docker/compose/issues/8056

 検証

docker-compose.yml

version: "3"
services:
  rest-client:
    container_name: curl
    image: tutum/curl
    command: sleep infinity

  web1:
    container_name: api1
    build: ./api1
    command: ruby main.rb -o 0.0.0.0

  api1:
    container_name: api2
    build: ./api2
    command: ruby main.rb -o 0.0.0.0

networks:
  default:
    name: net1

以上のようなケース、”api1”が異なるコンテナでそれぞれコンテナ名、サービス名で使われている場合だと、net1ネットワーク内だと名前解決の結果が混ざる。
嘘だろって思いますが、本当に混ざります。

 api1コンテナ

require 'sinatra'

get '/' do
  'This is app1 container!'
end

 api2コンテナ

require 'sinatra'

get '/' do
  'This is app2 container!'
end

これらをnet1内でアクセスするにはドメインにコンテナ名を使うことでURLアクセスできます。
つまり、以下の結果が期待できます。

#net1ネットワークに接続して、
$ curl "http://api1:4567/"
This is app1 container!
$ curl "http://api2:4567/"
This is app2 container!

ですが、curl "http://api1:4567/"の結果がランダムに変わります。

 テスト

$ docker-compose up -d
$ docker exec -it curl bash
# curl "http://api1:4567/"

こうしてやると、半分ぐらいの確率で、This is app2 container!の結果が混ざって帰ってきます。。。

謎の404エラーなどで困っている方がいれば、それが別のコンテナに運ばれている可能性があります。お気をつけて。。。

 手軽に試したい方へ

https://github.com/akihirof0005/Verification-defects
上記のリポジトリにテストケースを作成しました。
そして、協力してくれる方は、再現できたら教えてください。再現できなくても教えてください。。。。

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

EC-CUBE 4 の環境を、Windows + WSL2 + Docker で構築する

Windows 10 Pro 上に、新規に EC-CUBE の開発環境を構築する機会があったのでその手順メモです。

WSL2 + Docker を使って EC-CUBE 4.0 が起動するところまでをまとめます。

試した環境・バージョンは

  • Windows 10 Pro (バージョン 1909)
  • WSL 2 + Ubuntu 20.04LTS
  • Docker v20.10.2
  • EC-CUBE 4.0.5

1. Windows に WSL2 をインストール

まずは WSL2 (Windows Subsystem for Linux) のインストールから。

Microsoft の公式サイトに詳しいガイドがありますので、その手順どおりに進めていきます。(途中、再起動が必要な箇所もありました)

Linuxディストリビューションを選択してインストールする箇所では、今回は Ubuntu 20.04LTS を選んでいます。

2. Docker Desktop をインストール

以下から Docker Desktop をダウンロード、からのインストール。

3. EC-CUBE をダウンロード

今回は GitHub の EC-CUBE のリポジトリからクローンしてきます。

Ubuntu のターミナルを開き、適当なフォルダにて以下コマンドで。

git clone https://github.com/EC-CUBE/ec-cube.git

4. Docker のビルド

EC-CUBE のフォルダに移動して、docker build します。

cd path/to/ec-cube
docker build -t eccube4-php-apache .

5. Docker の初回起動

ローカルの EC-CUBE のディレクトリをマウントしつつ、Docker を起動します。

docker run --name ec-cube -p "8080:80" -p "4430:443" -v "$PWD/html:/var/www/html/html:cached" -v "$PWD/src:/var/www/html/src:cached" -v "$PWD/app:/var/www/html/app:cached" eccube4-php-apache

これで EC-CUBE が起動しました。

ブラウザで http://localhost:8080/ にアクセスして、ストアの画面が表示されていれば成功です。

管理画面へのログインは http://localhost:8080/admin/ にて、初期ID/パスワードは admin password です。

Docker の終了は ctrl + c で。

6. 2回目以降の起動

2回目以降の起動は、以下のコマンドでOKです。

docker start --attach ec-cube

参考

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

gem wheneverをdockerで使う

環境

Docker Engine 20.10.2
Ruby 2.7.0
Bundler 2.1.4

手順

wheneverをGemfileへ

# Gemfile

source 'https://rubygems.org'
git_source(:github) do |repo| "https://github.com/#{repo}.git" end

gem 'whenever'

コンテナにcronをインストール

# Dockerfile

FROM ruby:2.7.0

RUN apt-get update && apt-get install -y cron && apt-get install -y vim

WORKDIR /usr/src/app
COPY Gemfile .
COPY Gemfile.lock .
RUN bundle install

コンテナのsetupとwheneverの設定

$ docker build -t test_image .
$ docker create --name="test_container" -it -v "$PWD":/var/src/app test_image
$ docker start test_container
$ docker exec -it test_container /bin/bash
/usr/src/app# bundle exec wheneverize .

以下の設定ファイルができるのでカスタマイズする

# schedule.rb

#
# Use this file to easily define all of your cron jobs.
#
# It's helpful, but not entirely necessary to understand cron before proceeding.
# http://en.wikipedia.org/wiki/Cron

# Example:
#
set :output, "log/cron_log.log"
#
every 1.hours do
  # command
end
#
# every 4.days do
#   runner "AnotherModel.prune_old_records"
# end

# Learn more: http://github.com/javan/whenever

もう一度コンテナに入りコマンドを実行

$ docker exec -it test_container /bin/bash
/usr/src/app# bundle exec whenever
# =>
# 0 0,2,4,6,8,10,12,14,16,18,20,22 * * * /bin/bash -l -c '/usr/bin/some_great_command >> /path/to/my/cron_log.log 2>&1'
# 0 0,2,4,6,8,10,12,14,16,18,20,22 * * * /bin/bash -l -c 'cd /usr/src/app && bundle exec script/runner -e production '\''MyModel.some_method'\'' >> /path/to/my/cron_log.log 2>&1'
# 0 0,2,4,6,8,10,12,14,16,18,20,22 * * * /bin/bash -l -c 'cd /usr/src/app && RAILS_ENV=production bundle exec rake some:great:rake:task --silent >> /path/to/my/cron_log.log 2>&1'
# 0 0 1,5,9,13,17,21,25,29 * * /bin/bash -l -c 'cd /usr/src/app && bundle exec script/runner -e production '\''AnotherModel.prune_old_records'\'' >> /path/to/my/cron_log.log 2>&1'

cronを起動

/usr/src/app# service cron start
#=> [ ok ] Starting periodic command scheduler: cron.

cronが動いているか確認

/usr/src/app# service cron status
#=> [ ok ] cron is running.

参考

gem whenever

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

dockerコンテナ作った(Dockerfileから)

イメージの作成

*コンテナ起動時にapacheが自動起動しない・・・なぜだ

Dockerfileを準備

mkdir -p /usr/local/etc/docker_files/test/
vi /usr/local/etc/docker_files/test/Dockerfile
FROM ubuntu

RUN apt-get update
RUN apt-get -y upgrade
RUN apt-get install -y sudo
RUN sudo apt-get install -y vim
RUN sudo apt-get install -y curl
RUN sudo apt-get install -y tzdata
RUN sudo apt-get install -y php7.4

ADD ./home /home/
ADD ./php.ini /usr/local/etc/php/
ADD ./apache2 /usr/local/etc/
COPY ./startup.sh /usr/local/etc/
RUN chmod 744 /usr/local/etc/startup.sh

RUN ["sudo", "/bin/bash", "-c", "echo \"ServerName $HOSTNAME\" > /etc/apache2/conf-available/fqdn.conf"]
RUN a2enconf fqdn
#RUN apachectl start

EXPOSE 80
CMD ["/usr/local/etc/startup.sh"]
#ENV APACHE_RUN_USER www-data
#ENV APACHE_RUN_GROUP www-data
#ENV APACHE_PID_FILE /var/run/apache2.pid
#ENV APACHE_RUN_DIR /var/run/apache2
#ENV APACHE_LOG_DIR /var/log/apache2
#ENV APACHE_LOCK_DIR /var/lock/apache2
#CMD ["apachectl", "-D", "FOREGROUND"]
#RUN ["sudo", "/bin/bash", "-c", "/etc/init.d/apache2 start"]
#RUN ["sudo", "/bin/bash", "-c", "/usr/sbin/apachectl -D FOREGROUND"]

Dockerfileからイメージを作成

イメージあるかどうか確認

docker image ls
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE

ビルド(イメージを作成)

docker build -t test /usr/local/etc/docker_files/test/

できたかどうか確認

docker image ls
REPOSITORY   TAG       IMAGE ID       CREATED          SIZE
php74test    latest    b5f7bfd05352   58 seconds ago   297MB
ubuntu       latest    f63181f19b2f   24 hours ago     72.9MB

コンテナ作成

docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
docker run --name container01 -it php74test:latest /bin/bash

Ctrl + P + Q でコンテナから出る
docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
a3270221bbd8   php74test:latest   "/bin/bash"   54 seconds ago   Up 53 seconds             container01
docker attach container01
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

docker, docker-composeを ubuntu18にワンライナーインストール

概要

これを実行すること。

sudo apt-get update &&\
sudo apt-get -y 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 add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable" &&\
sudo apt-get update &&\
sudo apt-get install -y docker-ce docker-ce-cli containerd.io &&\
sudo apt-get install -y docker-compose

備考

この後 docker login で謎のgoのpanicエラー(sigfault的な)が出た時は
https://qiita.com/kenmaro/items/1adc71b42088f12d1b95
これを実行する。

また、

ERROR: Couldn't connect to Docker daemon at http+docker://localunixsocket - is it running?

If it's at a non-standard location, specify the URL with the DOCKER_HOST environment variable.
Makefile:5: recipe for target 'config' failed
make: *** [config] Error 1

が発生した場合、

https://qiita.com/dnnnn_yu/items/14a31721a2870b735938

ここをフォローすること。(記事ありがとうございます。)

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

dockerをubuntuにインストール後、docker login できない問題解決備忘録

概要

$ docker login registry.gitlab.com
等のコマンドで、

 SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x5647add8ed76]

goroutine 1 [running]:
github.com/docker/cli/cli/command.ConfigureAuth(0x5647af9cfce0, 0xc00050d6c0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x5647af93f100, 0xc000414eb0, 0xc00059b968)
    /go/src/github.com/docker/cli/cli/command/registry.go:128 +0x46
github.com/docker/cli/cli/command/registry.runLogin(0x5647af9cfce0, 0xc00050d6c0, 0x7ffdf63d38a5, 0x13, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
    /go/src/github.com/docker/cli/cli/command/registry/login.go:123 +0x223
github.com/docker/cli/cli/command/registry.NewLoginCommand.func1(0xc000138dc0, 0xc0005e37f0, 0x1, 0x1, 0x0, 0x0)
    /go/src/github.com/docker/cli/cli/command/registry/login.go:45 +0xcc
github.com/docker/cli/vendor/github.com/spf13/cobra.(*Command).execute(0xc000138dc0, 0xc000364410, 0x1, 0x1, 0xc000138dc0, 0xc000364410)
    /go/src/github.com/docker/cli/vendor/github.com/spf13/cobra/command.go:850 +0x462
github.com/docker/cli/vendor/github.com/spf13/cobra.(*Command).ExecuteC(0xc000139b80, 0xc000364400, 0x2, 0x2)
    /go/src/github.com/docker/cli/vendor/github.com/spf13/cobra/command.go:958 +0x34b
github.com/docker/cli/vendor/github.com/spf13/cobra.(*Command).Execute(...)
    /go/src/github.com/docker/cli/vendor/github.com/spf13/cobra/command.go:895
main.runDocker(0xc00050d6c0, 0x5647af941de0, 0xc000010020)
    /go/src/github.com/docker/cli/cmd/docker/docker.go:287 +0x1d3
main.main()
    /go/src/github.com/docker/cli/cmd/docker/docker.go:298 +0xf3

となる。。

解決方法

sudo apt remove golang-docker-credential-helpers

とりあえずこれで大丈夫になる。。

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

M1 MacでDocker Preview版が起動しなくなった。

事象

ある日突然Docker Preview版が起動しなくなりました。
何もしてないのに...

解決方法

以下のIssueを参考にしました。

https://github.com/docker/for-mac/issues/5276

まず以下を試しました

Kubernetesを無効化(効果なしでした)

k8s is known not to work, I had to edit ~/Library/Group\ Containers/group.com.docker/settings.json ("kubernetesEnabled": false, "kubernetesInitialInstallPerformed": false) to get the dashboard to respect that I wanted to back out that change
that said, the perpetual starting state problem happened to me long after I tried to enable k8s
edit: when docker was working, I was using k3d successfully

で、以下を試したところ起動しました(FireWallをOFFにする)

ちなみにファイアーウォールオプションから、Docker Previewを外部アクセス許可してもだめだったので、ファイアーウォール自体をオフにしないとダメっぽいです。

Try to close the firewall on mac m1 and then restart the docker.

結論

原因はわかりませんが、Mac側のファイアウォールが起動を妨げていた模様。

セキュリティ的に問題ありそうですが、一応は動くようになったので解決です。

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

M1 MacでDockerが起動しなくなった。

事象

ある日突然Docker Preview版が起動しなくなりました。
何もしてないのに...

解決方法

以下のIssueを参考にしました。

https://github.com/docker/for-mac/issues/5276

まず以下を試しました

Kubernetesを無効化(効果なしでした)

k8s is known not to work, I had to edit ~/Library/Group\ Containers/group.com.docker/settings.json ("kubernetesEnabled": false, "kubernetesInitialInstallPerformed": false) to get the dashboard to respect that I wanted to back out that change
that said, the perpetual starting state problem happened to me long after I tried to enable k8s
edit: when docker was working, I was using k3d successfully

で、以下を試したところ起動しました(FireWallをOFFにする)

ちなみにファイアーウォールオプションから、Docker Previewを外部アクセス許可してもだめだったので、ファイアーウォール自体をオフにしないとダメっぽいです。

Try to close the firewall on mac m1 and then restart the docker.

結論

原因はわかりませんが、Mac側のファイアウォールが起動を妨げていた模様。

セキュリティ的に問題ありそうですが、一応は動くようになったので解決です。

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

Dockerいれてみた 

サーバの用意

まずはさくらにログインして最小構成でUbuntu選んで適当にサーバ作る

ユーザの作成

作成完了したら、デフォルトのユーザでログイン後、
adduser USER
を実行してユーザを作成する。

dockerインストール

参考)公式
https://docs.docker.com/engine/install/ubuntu/

apt-get update

sudo apt-get install -y \
    apt-transport-https \
    ca-certificates \
    curl \
    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=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

sudo apt-get install docker-ce docker-ce-cli containerd.io

ここまでやればdocker使えるようになる

ちなみにdockerコマンドをsudoしないで使いたいなら
dockerグループにユーザ追加すればOK

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

OpenJDKコンテナにDockerを追加

FROM openjdk:8-jdk

RUN apt-get update -qq && apt-get install -qqy \
    apt-transport-https \
    ca-certificates \
    curl \
    lxc \
    iptables

RUN curl -sSL https://get.docker.com/ | sh

CMD service docker start && /bin/bash
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コンテナの話をはじめから 〜Kubernetesを本番運用して5年目の所感まで〜

この記事は、ベルフェイスの有志メンバーでつなぐ 新年ベルリレー 20日目のコンテンツです。

はじめに

ベルフェイスでは、本番サービス運営のためにコンテナ技術 (Kubernetes = クーバネティス) を利用しています。

本項の執筆者 @numa-numa は転職して日が浅いのですが、以前からKubernetes (これより先は、主にK8sと記載します) を本番で運用してきました。
私にとってコンテナで商用サービスを扱うようになってもうすぐちょうど5年…という節目の年でもあるので、コンテナのことを基本からまとめながら、K8sの何が良いのか/悪いのかという経験に基づいた概観についてまでご紹介する内容にしていきたいと思います。

【歴史】 2000年代半ばくらいから一気に隆盛を極めた仮想技術

いわゆる、コンピュータの仮想化と言われる技術が多用されるようになったのは、2000年代半ば (2005年前後?) が黎明期であり、それから数年の間に一気に多用されるようになりました。

コンピュータを仮想化するようになった背景要因として、ハードウェアの高性能化が挙げられます。
WEBサービスを提供する時に、フロント系サーバ群にはWEBサーバ (Apacheなど) や開発言語 (主にPHPを利用したものやRailsなどの各種フレームワーク) などをインストールして多数台の冗長構成で利用することが一般的です。

ただ、徹底したチューニングを施したとしても、OSの制約などでサーバ1台で捌けるアクセス量もある程度上限が決まってきます。
サーバリソースは使えるだけ有効に使いたいものですが、台数を増やす前にサーバ1台の性能が大きすぎて非効率…という状況も往々にして発生していました。

そこで、物理ベースのサーバには仮想化のソフトウェアをインストールすることで、1台の物理サーバのリソースを分割し何台かのサーバを内部に収容するタイプの仮想技術が使われるようになりました。

イメージ的には以下の図のような構成概念になります。
hypervisor_diagram.jpg
これは、細分化すると、

  • ホストOS型 (VMware Fusion, Vagrant, VirtualBox など)
    => OSはWindow/Linuxなどを利用し、仮想化用ツールをインストール
  • ハイパーバイザ型 (Esxi, KVM, Xen など)
    => OS自体が仮想化専用のもの

の2通りがあります。
ホストOS型は主にPCで使われる技術で本項の主旨とも外れるので、ここではサーバ用途に限定しハイパーバイザ型だけを図示しています。

【歴史+α】 コンテナとは何か?

さて、私が使ってきたK8sをはじめとしたコンテナ技術は仮想化技術です。

これがいわゆるハイパーバイザ型と何が違うのかというと、Linuxのコンテナ層というOSのカーネルの機能を利用して仮想化を行っている点です。
具体的には、 namespacescgroup という機能を利用しています。詳細は割愛しますが、これらはK8sの動作についても重要な役割を持っています。

  • namespaces … 実行環境を名前空間として切り分けることで、コンテナ間の分離・独立性を確保する
  • cgroup … CPU・メモリ・Disk I/Oなどにリソース制限を設ける

これらの特性を利用することで、Linuxという1つのOSでも実行空間分離やリソースへの制限を設けることで、仮想的に複数環境を動作することができる仕組みです。

コンテナ型の仮想化は、下の図のような構成概念となります。
Container_diagram.jpg
Linuxにおけるコンテナ技術というのは比較的歴史があり、cgroupの元になるカーネル技術は2008年頃に開発されていて、当時からカーネル機能を利用したLXCという技術も開発されています。
その他、初期から独自のコンテナを展開してきたものとしてOpenVZというのがありますし、libvirt, systemd-nspawn, FreeBSD Jail など、実はいろいろなコンテナ技術があります…

しかしながら、2021年初現在では、コンテナ ≒ Docker と言って差し支えない昨今です。
https://www.docker.com/company

Dockerは2013年3月に急遽出てきた技術といえるでしょう。
それなのに、これが現在世界のコンテナの標準技術となっているのです。

Dockerがデファクトスタンダードになった理由は実際判然としないのですが、

  • 単純に、市場のニーズに対するリリースタイミングがよかった
  • 軽量さとシンプルさ、手軽な利用性
  • 結果的に多くのLinuxディストリビューションに加え、Microsoft/Googleなどでも導入された

などではないかと、個人的には考えています。

Kubernetesとは何か?

K8sはDockerを運用するためのオーケストレーションツールです。

Dockerはそれだけを使っても、スポットでだけ生存する単純な仮想環境 (コンテナ) を作成し検証作業などに利用することしかできません。

WEBサーバ・DBサーバ・ストレージサーバ・KVS……
WEBサービスを商用展開する場合には、単一のコンテナがあれば良い訳ではなく、複数種のコンテナを立てそれらを相互連携できるスキームが必要です。
それを提供するのがオーケストレーションツールということになります。

K8sはコンテナオーケストレーションツールのデファクトスタンダードです。

Dockerの世界と違い、ことコンテナオーケストレーションに関しては、ここ数年はレッドオーシャンの状態が続いていました。
しかし、今はその戦いにひとまず決着がつき "K8sがデファクトだ!" と言い切ってほぼ問題ない状況だと考えています。
(ITのことなので、今後これがひっくり返らない保証もないのですが…)

コンテナ (Docker) を使うと何がいいの?

結論からいうと、開発/運用における下記の5つの課題が解決されます。

  1. 開発環境をすぐに立てることも、消すこともできる (環境の自由)
  2. アプリケーションの実行環境 (多くはインフラ的な領域) の構成方法をコードとして定義することで、結果的に運用負荷が低減される
  3. 本番/ステージング/開発 各環境の差異がなくなり、アプリケーションリリースに対する心理的安全性が高まる
  4. パッチ適用やカーネルアップデートが容易になる (それらがすぐ行えるかどうかの確認も含め)
  5. CIを整備することで、安定的なデリバリーが確保される

これらについて、単純な例でかんたんに説明します。

ここでは、WEBプログラムを用いない単純なWEBサーバをローンチすることを考えます。
Apacheをインストールし、テストページが見えればOKです:smile:

一般的なサーバの場合

当たり前ですが、もし物理サーバを用いるとすると、まずはハードウェアを用意し、そこにOSをインストールするキッティングから始まります:cyclone:
ただ、今はクラウドがありますので、私の方ではAWSを利用して Ubuntu がインストールされた VM(EC2) を立ててrootログインし、以下のようなコマンドを実行しました。

apt-get install -y apache2
systemctl start apache2

ブラウザを表示した結果は、以下の通りです。
test_apache01.png
OS標準のApacheテストページが見えるようになっています。

Dockerの場合

Dockerではインフラ構成をコードにします。
このコード (Dockerfile) をもとにインフラ/アプリケーションをデプロイします。

通常、商用で利用するときは何らかのCIツールを使用することになりますが、ここではPC(Mac)でDockerfileを記載し、コマンドでコンテナを実行することにします。

Dockerfileは以下のような内容です。

FROM alpine:3.10

# Package Install
RUN apk update && apk add --no-cache apache2

# Run apache2
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]

Dockerfileが書けたら、以下のようにコマンドを実行しDockerをビルド/実行します。

docker build -t test-apache ./
docker run --name test-apache -d -p 80:80 test-apache

こちらのブラウザ表示結果は、以下の通りです。
test_apache02.png
ここでは Alpine というOSを利用しています。Alpine は非常に軽量なため、一般にコンテナでの使用が推奨されます。
OSなどが違っているので、テストページの見た目は全く異なっていますが、WEBサービスが構築できるという本質は同じです。

どういい所につながる?

Dockerは "定義(宣言)型インフラストラクチャ" と言われます。
対して、ログインしコマンドコントロールするものは "命令型インフラストラクチャ" と言います。

命令型は、エンジニア (あるいはオペレータ) がコマンド操作を行うことで、自由に状態や構成を変化させることができます。
対して定義型は、コードによって定義された一定の状態を保ち続けることになります。

一見、前者の方が良いように感じますが、実は定義型を採用するだけで先に挙げた5つの課題解決に結びつくのです。

一つ一つ見ていくことにしましょう。

  • 開発環境をすぐに立てることも、消すこともできる (環境の自由)
    もし物理サーバでも構築しようものなら、破棄するときにはデータ消去とサーバ回収の業者まで呼ぶことになります。
    クラウドを利用する場合も、手動で立てたサーバを消し忘れれば、どんどんお金はかかります。
     
    Dockerコンテナは、以下のようなコマンド1つで揮発します。
    (K8sの場合は別のコマンド体系を利用することになります。)
docker stop e3d51562fb72
  • アプリケーションの実行環境 (多くはインフラ的な領域) の構成方法をコードとして定義することで、結果的に運用負荷が低減される
    人がコンピュータに命令を行う=運用作業…です。つまり、コンテナの利用範囲が広がれば広がるほど運用作業は少なくなります。

  • 本番/ステージング/開発 各環境の差異がなくなり、アプリケーションリリースに対する心理的安全性が高まる
    開発だけインストールされているモジュールのバージョンが異なる…
    ステージングだけサービス止まってた…
    などは、WEBベンチャー企業を中心によくある話です。
    コンテナを使うことで、こうしたことは起きなくなるか、相当起こりにくくなります。
    どの環境も、同じDockerfileをもとに構成されるためです。

  • パッチ適用やカーネルアップデートが容易になる (それらがすぐ行えるかどうかの確認も含め)
    OSのカーネルアップデート。命令型のインフラでこれを行おうとすると、サービスの停止やサーバの切り離しを伴う数時間の作業が必要です。
    そして、それら(本番)の作業に至るまでの検証作業も…
     
    コンテナの場合。ここでは Alpine の3.10に特有の脆弱性があると仮定し、それが3.12で修正されたとします。
    3.12でサービスが稼働するかの確認は、Dockerfileの先頭行を以下のように直してコンテナを作り直せばすぐにできます。

FROM alpine:3.12
  • CIを整備することで、安定的なデリバリーが確保される
    先ほど実行したように、手動オペレーションでDockerイメージを実行するやり方はPCのみに通用するものです。 商用サービスへの適用検討すると、

 ・ビルド
 ・テスト
 ・デプロイ

 のフローを厳密化する必要が生じ、それを機にフローを設計(改善)することとなり、結果的に安定したデリバリー確保につながります。

Kubernetesを使うと何がいいの?

まず、K8sはDockerのオーケストレーションツールですので、Dockerで享受できるいいことは同様に全て当てはまります。

K8sは非常に多機能であり多くのメリットがあるのですが、本項の内容に即した3点に絞ってご紹介します。

複数のDockerホストの管理

Dockerを1台のホスト(サーバ)で構成すると、故障などでホストが停止した時に全サービスが停止することになります。
ハイパーバイザ型の仮想化では、こうしたことがしばしば問題になってきました。
K8sでは複数のDockerホストを一元管理することによって、冗長性・高可用性を確保することが可能です。

スケーリング/オートスケーリング

K8sでは、サーバ1台が Pod と呼ばれる単位で構成されます。
Podの数や性能は自由に定義できます。Podの性能を変更したいときは、コードを変更し再リリースを行うだけです。
アクセス量によってPod数が調整される、オートスケーリングも簡単に実装できます。

オートヒーリング

Dockerではオペレーションを行うことでコンテナの内容が変わってしまった時に、再生成することで定義された状態に戻すことができます。
K8sではこれを一歩進め、コンテナに異常 (過大なアクセスによるリソース枯渇など) が起こりダウンしてしまった時にPodは自動で復旧されます。

Kubernetesの構成概念

WEBにおいては、以下のようなものが基本となります。

K8sではさまざまな種類のコンテナをデプロイすることができるのですが、下図は Deployment と言われる種類のものを例に取っています。
Deployment はWEBのフロントアクセス系に最も適したリソースで、リリースを行うことで継続的にコンテナの更新を行うことが可能です。
Deployment_diagram.jpg

  • Pod
    実際にデプロイされるコンテナです。サーバ1台と同様のものと考えて差し支えありません。
    Podはオートスケールで数を変更することもできますし、固定の数を指定しておくこともできます。
    デプロイされるアプリケーションに応じて、CPU/メモリの割当て量を調整して構成します。

  • Namespace
    仮想のクラスタ空間であり、それぞれは分離されていて独立しています。
    Namespaceをいくつか用意することで、複数のチームで利用したり、複数のアプリケーションを同じ(物理)K8sクラスタにデプロイすることが可能です。

このように概念を見ていくと、K8sで使われる技術はLinuxコンテナの技術の応用であることにも気づかれるでしょう。

Kubernetesを運用するうえで出てくる問題点

私のこれまでの経験でも、またベルフェイスでもそうなのですが、K8sをツールとしてインストール/運用したりDockerホストを構築したりすることは行っていません。

AmazonやGoogleのクラウドサービスで提供されるマネージドサービスでK8sを利用しています。

マネージドサービスを利用するとK8s自体の複雑な管理/運用は不要 (クラウド任せ) になるので、エンジニアはより開発に注力できることになります。
ただし、運用面で何もしなくて良いわけでは当然なく、私がこの5年間で実感した K8sのマネージドサービスを使う上での問題点 に絞って2点ご紹介します。

バージョンアップのつらみ

K8sは仕様こそある程度落ち着いてきましたが、現在も活発に開発が進んでいます。
2021年1月現在の最新は、v1.20.0ですがこれもすぐに過去のバージョンとなってしまうことでしょう。
https://kubernetes.io/docs/setup/release/notes/#downloads-for-v1-20-0

K8sはOSSであり、ベンダーニュートラルなツールです。
ただ、マネージドサービスはベンダーディペンドなので、この間の差はユーザが埋めることになります。

具体的には、クラウド側ではある時点で新規インストールできるバージョンとサポートするバージョンが決められているということになります。
ユーザは定期的にマネージドのK8sクラスタのバージョンを上げる運用が必要になります。
バージョンアップにより、K8sとして仕様が変わり最悪デプロイされたアプリケーションが動作しなくなる可能性もあるので注意が必要です。

慣れてしまえば、ポイントは決まっているのでバージョンアップは恐怖の作業ではないですが、それでもつらみの運用とはいえるでしょう。

キャパシティプランニングは慎重に

先述の通り、K8sはPodのオートスケーリングが可能ですので、本番運用ではぜひ採用/設定すべきです。

しかし、Pod単体のキャパシティプランニング (利用リソース量調整) まで自動で行ってくれるわけではありません。
たとえば、アプリケーションの動作のために、

  • 2vCPU
  • 2GBメモリ

という要件のところ、たとえばこれを下回る以下のような設定を行ったとすると記載のような不具合を生じます。

  • 1vCPU … CPU使用率が張り付いてパフォーマンスが相当に悪化
  • 1GBメモリ … コンテナ内部でOOM (Out Of Memory) が引き起こされ、Podが上がってもすぐに落ちる :fearful:

とくに、私はメモリ不足による一大インシデントを経験しています。
キャパシティプランニングほどITインフラにとって重要なものはないので、十分に余裕を見た設計が肝要です。

おわりに

ここ15年くらいの仮想の歴史を繙きながら、コンテナのことをいろいろ書いてきましたが、結局のところシステムにおける運用負荷を完全に0にすることはできません。

ただし、コンテナを活用することで可能な限りの運用効率化・可視化・負荷低減施策など継続的なプロセス改善を行い、限りなく0に近い運用負荷水準にすることは可能だと考えています。

ベルフェイスでは、AWSを利用したコンテナ活用を推進しておりまして、今後も安定性の高いシステム基盤作りに取り組んでいきます。

ベルフェイスは,現在積極採用中です:smiley:
一緒にOpslessに取り組みたい人いませんか:interrobang:
https://recruit.bell-face.com/

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

golangでFargate運用を想定したDockerfile作成(Alpineベース)

概要

個人アプリにて、Fargateでのコンテナ運用を行うため、golang環境のDockerfileを作成しました。

当環境の特徴として、

  • DockerイメージをAlpine Linuxベースを使用し、軽量化。
  • マルチステージビルド機能を使用し、ビルド環境でgolangアプリやその他バイナリを作成し、軽量化。
  • Fargateで運用するコンテナの中に入ってシェル操作するため、ssm-agentを導入。

です。

各種ファイル

Dockerfile

FROM golang:1.14.4-alpine3.12 as builder

ARG SSM_AGENT_VERSION=2.3.1205.0

RUN apk add --no-cache \
         'make~=4.3-r0' \
         'git~=2.26.2-r0' \
         'gcc~=9.3.0-r2' \
         'libc-dev~=0.7.2-r3' \
         'bash~=5.0.17-r0'

RUN wget -q https://github.com/aws/amazon-ssm-agent/archive/${SSM_AGENT_VERSION}.tar.gz && \
    mkdir -p /go/src/github.com && \
    tar xzf ${SSM_AGENT_VERSION}.tar.gz && \
    mv amazon-ssm-agent-${SSM_AGENT_VERSION} /go/src/github.com/amazon-ssm-agent && \
    echo ${SSM_AGENT_VERSION} > /go/src/github.com/amazon-ssm-agent/VERSION

WORKDIR /go/src/github.com/amazon-ssm-agent

RUN gofmt -w agent && make checkstyle || ./Tools/bin/goimports -w agent && \
    make build-linux

WORKDIR /go/src/server

COPY go.mod go.sum ./

RUN go mod download

RUN go get bitbucket.org/liamstask/goose/cmd/goose

COPY . .

RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o /go/bin/server

FROM alpine:3.12 as prod

RUN apk add --no-cache \
      'aws-cli~=1.18.55-r0' \
      'sudo~=1.9.0-r0' \
      'mysql-client~=10.4.15-r0'

RUN adduser -D ssm-user && \
    echo "Set disable_coredump false" >> /etc/sudo.conf && \
    echo "ssm-user ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/ssm-agent-users && \
    mkdir -p /etc/amazon/ssm

COPY --from=builder /go/src/github.com/amazon-ssm-agent/bin/linux_amd64/ /usr/bin
COPY --from=builder /go/src/github.com/amazon-ssm-agent/bin/amazon-ssm-agent.json.template /etc/amazon/ssm/amazon-ssm-agent.json
COPY --from=builder /go/src/github.com/amazon-ssm-agent/bin/seelog_unix.xml /etc/amazon/ssm/seelog.xml
COPY --from=builder /go/bin/server /go/bin/server
COPY --from=builder /go/bin/goose /go/bin/goose

RUN mkdir -p /go/bin/db
COPY ./db/dbconf.yml /go/bin/db/dbconf.yml
COPY ./db/migrations /go/bin/db/migrations

COPY ./db/mysql/init /docker-entrypoint-initdb.d

EXPOSE 8080

COPY ./aws/docker-entrypoint.sh /

CMD ["sh", "/docker-entrypoint.sh"]

docker-entrypoint.sh

#!/bin/sh

set -e

amazon-ssm-agent -register -code $SSM_ACTIVATE_CODE -id $SSM_ACTIVATE_ID -region "ap-northeast-1"
amazon-ssm-agent &

/go/bin/server

要点

Alpineはssmエージェント未対応

※一部抜粋
RUN wget -q https://github.com/aws/amazon-ssm-agent/archive/${SSM_AGENT_VERSION}.tar.gz && \
    mkdir -p /go/src/github.com && \
    tar xzf ${SSM_AGENT_VERSION}.tar.gz && \
    mv amazon-ssm-agent-${SSM_AGENT_VERSION} /go/src/github.com/amazon-ssm-agent && \
    echo ${SSM_AGENT_VERSION} > /go/src/github.com/amazon-ssm-agent/VERSION

Alpineではssmエージェントのパッケージがないので、ソースから拾いビルドして設置する必要があります。
https://github.com/aws/amazon-ssm-agent/issues/140

ECRスキャンはscratchベース非対応

FROM alpine:3.12 as prod

Dockerイメージ軽量化のため、最初はscratchベースで実行環境を構築しようとしましたが、ECRはイメージスキャン未対応のことなので、実行環境もAlpineを採用しました。
https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/image-scanning-troubleshooting.html

マイグレーションツールのgooseを採用

RUN mkdir -p /go/bin/db
COPY ./db/dbconf.yml /go/bin/db/dbconf.yml
COPY ./db/migrations /go/bin/db/migrations

開発環境でもお世話になったgooseを本番環境でも採用しました。ビルド環境でバイナリ作成、実行環境にバイナリと必要なファイルをコピーして準備完了。ファイルの置き場所によって設定ファイルdbconf.ymlが読み込まれなくなってしまうので、注意が必要です。

シェルスプリクトで起動コマンド設定

amazon-ssm-agent -register -code $SSM_ACTIVATE_CODE -id $SSM_ACTIVATE_ID -region "ap-northeast-1"
amazon-ssm-agent &

コンテナ内で実行するため、シェルスクリプトでコマンドを投げてあげます。この時アクチベーションキーも設定しないといけないので、コンテナ内の環境変数に設定します。

参考資料

Go 1.12 の開発環境と本番環境の Dockerfile を考える
Alpine Linux に amazon-ssm-agent をインストールする
AWS Fargateで動かしてるコンテナの中に入る方法

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

Myリポジトリの利用とDocker Registoryの構築。

はじめに

普段Dockerを利用する際は、初めに登録したDockerHUBのリポジトリからイメージ取得がされている。
これに特別困っていることはないのだが、DockerHUBにMyリポジトリを作ったり、ローカルでDocker Registoryを構築したりもせっかくなので試してみようと思った。

実行環境

・VMインスタンス2台(GCP上)

【VM#1(リージョン:東京)】
 ・Ubuntu 20.04 LTS
 ・docker 19.03

【VM#2(リージョン:US)】
 ・Ubuntu 20.04 LTS
 ・docker 19.03
 ・docker-registory

今回の手順

1.VM環境準備
2.DockerHUBにMyリポジトリ作成
3.Docker Registoryの構築

1.VM環境の構築

VM#1、VM#2にdockerのインストール
 【Dockerコンテナ内のUbuntuではsystemctlは使えない】の手順1を参考に。

2.DockerHUBにMyリポジトリ作成

DockerHUBへのアカウント登録
 DockerHUBの公式ページに飛び、サインアップ。
  https://hub.docker.com/

VM#1にPush用のイメージを用意

$ docker container run -it -d --name con1 ubuntu:18.04

コンテナに入り適当なソフトをインストール
 ※今回もApache2をインストール

コンテナに入る
$ docker attach con1
コンテナ内のコマンド
apt update
apt -y upgrade 
apt install -y apache2
コンテナ内のコマンド(コンテナから出る)
exit

変更を加えたコンテナをイメージ化する

$ docker commit con1 test-myrepo:ver1

イメージの確認

$ docker image ls
REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
test-myrepo   ver1      754107070068   54 seconds ago   213MB
ubuntu        18.04     2c047404e52d   3 weeks ago      63.3MB

MyリポジトリにイメージをPush

まずはDockerHUBにログインする

$ sudo docker login
Username: ******
Password: ******

Login Succeeded

tagコマンドでレジストリ先・リポジトリを変更したものを用意。

$ docker image tag 【イメージID】 【アカウント名(Myリポジトリ)】/【イメージ名】:【タグ】

試しにイメージを確認してみる。

$ docker image ls
REPOSITORY                 TAG       IMAGE ID       CREATED        SIZE
test-myrepo                ver1      754107070068   19 hours ago   213MB
******/new-img             ver1      754107070068   19 hours ago   213MB
ubuntu                     18.04     2c047404e52d   3 weeks ago    63.3MB

DockerHUBにイメージをPush

$ docker image push 【上記で作成されたイメージ名(アカウント含む)】:【タグ】

DockerHUBのページでリポジトリが作成されていれば、Pushは上手くいっている。

※普段docker image pullより、【イメージ名】:【タグ】のみでダウンロードできるのは、最初の設定時にデフォルトのレジストリ先を DockerHUB 、リポジトリ先をどこかに設定しているから。(上記のPushはリポジトリ先をMyリポジトリに変えている。)
例えば、プライベートレジストリにイメージをPushPullする時は、docker image pull 【レジストリ名】:【リポジトリ名】:【イメージ名】:【タグ】となる。

VM#2でMyリポジトリからイメージをPull

Pushの時と同じくCUIからDockerHUBにログインする

$ sudo docker login
Username: ******
Password: ******

Login Succeeded

実際のPullコマンドを実行

$ docker image pull 【アカウント名(Myリポジトリ)】/【イメージ名】:【タグ】

docker image lsコマンドなどで確認できれば成功!

ここまでできたら一旦VM#2のイメージは消す。

3.Docker Registoryの構築(プライベート用)

VM#2にDockerRegistory 取得

Registoryのイメージ取得

$ docker image pull registry

Registoryコンテナの起動

$ docker container run -d -p 5000:5000 registry

VM#1からDockerRegistoryにPushPull

レジストリ情報を付与したイメージを用意

$ docker image tag 【イメージID】 【DockerRegistoryの内部IP:5000】/【リポジトリ名】:【タグ】

プライベートRegistoryにPush

$ docker image push 【DockerRegistoryの内部IP:5000】/【リポジトリ名】:【タグ】
The push refers to repository [xxx.xxx.xxx.xxx:5000/******]
Get https://xxx.xxx.xxx.xxx:5000/v2/: http: server gave HTTP response to HTTPS client

しかし上記の様なエラーが出て上手く行かない。

別のdockerクライアントの端末からPushPullを行いたい場合、基本的にはSSLを使った暗号化通信が必要となる。
これはdockerクライアント側で、信頼関係がなく暗号化通信できないサーバーとは通信不可の設定になっているから。

今回は、Registryコンテナが入っているサーバーを限定的にhttp通信ができる様にする。

VM#1で以下を実行

daemon.jsonを作成

$ sudo nano /etc/docker/daemon.json
daemon.json
{"insecure-registries":["DockerRegistoryの内部IP:5000"]}

docker再起動

$ sudo systemctl restart docker

Inseure Registoryesに追加されているか確認

$ docker info
・・・
・・・
 Experimental: false
 Insecure Registries:
  xxx.xxx.xxx.xxx:5000
  127.0.0.0/8
 Live Restore Enabled: false
・・・
・・・

この状態で再度プライベートRegistoryにPush

$ sudo docker push 【DockerRegistoryの内部IP:5000】/【リポジトリ名】:【タグ】
The push refers to repository [xxx.xxx.xxx.xxx:5000/*******]
2a42637bbd9b: Pushing [====================>                              ]  62.14MB/149.7MB
fe6d8881187d: Pushed 
23135df75b44: Pushed 
b43408d5f11b: Pushing [========================================>          ]   51.5MB/63.25MB

ちゃんとPushできる事を確認!
 ※ちなみにPullも試したけど問題なくできた。

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