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

Docker+Rails+AWS(EC2+RDS)を使ってデプロイした

概要

AWSを使ってアプリケーションを公開している人は多く、私も実際に体験してみたくタイトル通りDockerで環境構築し、Railsでアプリケーションを開発し、AWSで実際にデプロイすることにチャレンジしました。
AWSは無料枠内にてデプロイまで目指します。

前提

  • アプリケーションはGithubを使って管理する。
  • 各サービスのアカウント登録は済ませている。(AWS、Github等)
  • AWSはIAMユーザーを作成し、必要なセキュリティ、ポリシーを割り当てている。
  • アプリケーションはDockerを使用して環境構築している。

AWSの設定

AWSのサービスの設定は極力IAMユーザーにて行います。まず、AWSにIAMユーザーでログインする。

  • VPCの作成

まずはVPCの作成を行います。VPCサービスのページを開き、メニューからVPCを選択。VPCの作成を選択します。
VPC名、CIDRブロックを設定し、VPCを作成します。

  • サブネットの作成

サブネットの作成を行います。
サブネットはEC2用のサブネットを1つ、RDS用のサブネットを2つ用意します。
メニューからサブネットを選択し、サブネットの作成を選択します。
先ほど作成したVPCを選択し、サブネット名、アベイラビリティゾーン、CIDRブロックを設定し、サブネットを作成を選択します。
※RDS用のサブネットはアベイラビリティゾーンを別々にします。

  • インターネットゲートウェイの作成

インターネットに接続するためにインターネットゲートウェイを設定します。
メニューからインタネットゲートウェイを選択し、インターネットゲートウェイの作成を選択します。
名前を設定し、インターネットゲートウェイの作成を選択します。
アクションからVPCにアタッチを選択し、作成したVPCにアタッチします。

  • EC2インスタンスの作成

EC2ダッシュボードに開き、インスタンスを起動を選択し、EC2インスタンスを作成します。
EC2インスタンスは無料枠で使えるマシンイメージとインスタンスタイプを選択します。
セキュリティグループは新しく作成します。
SSH接続を行いたいのでSSHの設定を行います。

タイプ プロトコル ポート範囲 ソース
HTTP TCP 80 0.0.0.0/0
SSH TCP 22 マイIP

設定に問題がなければ起動を選択します。
インスタンスを作成するときにキーペアを作成します。
キーペアはEC2にSSH接続する際必要となります。新しいキーペアの作成を選択し、キーペア名を設定しローカルにダウンロードしておきます。

インスタンスメニューの[ステータスチェック]が終了し、[インスタンスの状態]が[実行中]になれば、無事インスタンスが起動したこととなります。

続いてElastic IPを設定します。
メニューよりElastic IPを選択します。Elastic IP アドレスの割り当てを選択し、新しいアドレスの割り当てを選択し、割り当てを選択します。
作成したElastic IPを選択し、アクションからElastic IPアドレスの関連付けを選択します。
作成したEC2インスタンスを設定してElastic IPアドレスをEC2に関連付けます。

  • RDSの作成

RDSを作成する前に、RDS用のサブネットグループの作成を行います。
RDSメニューよりサブネットグループを選択し、DBサブネットグループの作成を選択します。

サブネットグループ名、VPCを選択し、RDS用に作成したサブネット2つを設定し、作成をします。
RDSサービスを開き、データベースの作成を選択します。
データベースはMySQLを選択します。基本的には既存の設定で大丈夫ですが、無料利用枠という箇所は忘れずに選択します。バージョン等は自身の使用するバージョンを設定します。

データベース名、マスターユーザー名、マスターパスワードは適宜設定します。
後に、Railsの設定に必要となります。(作成後、確認することができます)
作成したVPC、サブネットグループを選択します。セキュリティグループは新規作成を選択し、新しいセキュリティグループを作成します。
データベースの作成を選択し、データベースを作成します。

データベース用のセキュリティグループのインバウンドルールを変更します。

タイプ プロトコル ポート範囲 ソース
MYSQL/Aurora TCP 3306 EC2のセキュリティグループのID

Railsの設定

  • RDSの設定

RDSの情報をcredentials.yml.encに書き込みます。

docker-compose run -e EDITOR="vim" app rails credentials:edit
credentials.yml.enc
rds:
  host: RDSのエンドポイント
  database: RDSのデータベース名
  username: RDSのマスターユーザの名前
  password: RDSのマスターパスワード

config/database.ymlのproductionの箇所にRDSの情報を挿入します。

database.yml
#省略
production:
  <<: *default
  host: <%= Rails.application.credentials.rds[:host] %>
  database: <%= Rails.application.credentials.rds[:database] %>
  username: <%= Rails.application.credentials.rds[:username] %>
  password: <%= Rails.application.credentials.rds[:password] %>
  • Docker-compose.ymlの編集

データベースはRDSを使用するためdb:の箇所は全てコメントアウトします。volumes:のmysql-data:もコメントアウトします。
アプリケーションを本番環境で立ち上げるため、app:のcommand:に-e productionを追加します。

docker-compose.yml
version: '3'

services:
  # db:
  #   image: mysql:5.7
  #   command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
  #   env_file:
  #     - ./.env
  #   volumes:
  #     - mysql-data:/var/lib/mysql
  #   ports:
  #     - "4306:3306"

  app:
    build: .
    env_file:
      - ./.env
    command: bundle exec puma -C config/puma.rb -e production
    init: true
    volumes:
      - .:/myproject
      - public-data:/myproject/public
      - tmp-data:/myproject/tmp
      - log-data:/myproject/log
    # depends_on:
    #   - db

  web:
    build:
      context: containers/nginx
    init: true
    volumes:
      - public-data:/myproject/public
      - tmp-data:/myproject/tmp
    ports:
      - 80:80
    # depends_on:
    #   - app

volumes:
  # mysql-data:
  public-data:
  tmp-data:
  log-data:
  • nginx.comfの編集

server_nameのxx.xx.xx.xxの箇所にElastic IPアドレスを入力します。

nginx.conf
upstream myproject {
  server unix:///myproject/tmp/sockets/puma.sock;
}

server {
  listen 80;
  server_name xx.xx.xx.xx [or localhost];

  #省略
  }
}
  • その他の設定

その他Github等外部に知られたくないKEYや環境変数などは.envファイルを作成し、そちらに書き込みます。dotenv-railsを使うとGitを使用する際管理をし易くなります。

gemfile
gem 'dotenv-rails'
$ bundle install

.gitignoreファイルに.envファイルを記述することで、githubにpushされなくなります。

.gitignore
/.env

config/environmentsのproduction.rbを編集します。
下記内容を編集すると、本番環境で立ち上げ時に便利です。

production.rb
config.assets.js_compressor = Uglifier.new(harmony: true)
config.assets.compile = true

以上、完了したらアプリケーションをgithubへpushします。

AWSでアプリケーションをデプロイ

  • EC2のSSH接続する。

EC2にSSH接続するための設定を行います。

$ mkdir ~/.ssh
$ mv ~/Downloads/myapp.pem ~/.ssh/
$ chmod 600 ~/.ssh/myapp.pem
$ ssh -i ~/.ssh/myapp.pem ec2-user@xxx.xxx.xxx.xxx

myapp.pemはダウンロードしたキーペアの名前です。chmodで権限を変更後、キーペアを使用してEC2にログインします。ec2-userはAWS linuxのデフォルトユーザーです。xxx.xxx.xxx.xxxはEC2インスタンスのElastic IPを入力します。

まず初めにyumをアップデートします。

[ec2-user@ip-xxx-xxx-xxx-xxx ~]$ sudo yum update -y
  • EC2にDocker環境を作る

EC2にDockerとdocker-composeをインストールします。

# Dockerをインストール
[ec2-user@xxx.xxx.xxx.xxx ~]$ sudo yum install -y docker
[ec2-user@xxx.xxx.xxx.xxx ~]$ sudo service docker start
[ec2-user@xxx.xxx.xxx.xxx ~]$ sudo usermod -G docker ec2-user
[ec2-user@xxx.xxx.xxx.xxx ~]$ exit
$ ssh -i ~/.ssh/myapp.pem ec2-user@xxx.xxx.xxx.xxx
[ec2-user@xxx.xxx.xxx.xxx ~]$ sudo chkconfig docker on
# docker-composeをインストール
[ec2-user@xxx.xxx.xxx.xxx ~]$ sudo curl -L "https://github.com/docker/compose/releases/download/インストールするバージョン/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
[ec2-user@xxx.xxx.xxx.xxx ~]$ sudo chmod +x /usr/local/bin/docker-compose
  • gitをインストール

Githubからアプリケーションをクローンするためにgitをインストールします。

[ec2-user@xxx.xxx.xxx.xxx ~]$ sudo yum install -y git
[ec2-user@xxx.xxx.xxx.xxx ~]$ git clone [Githubのパス]
  • ローカルから必要ファイルをコピー

credentialsの解読するためのmaster.keyと.envファイルをローカルからコピーします。

[ec2-user@xxx.xxx.xxx.xxx ~]$ exit
$ scp -i ~/.ssh/myapp.pem master.key ec2-user@xx.xxx.xxx.xx:myapp/config/
$ scp -i ~/.ssh/myapp.pem .env ec2-user@xx.xxx.xxx.xx:myapp/
  • コンテナの起動
$ ssh -i ~/.ssh/myapp.pem ec2-user@xxx.xxx.xxx.xxx
[ec2-user@xxx.xxx.xxx.xxx ~]$ cd myapp
[ec2-user@xxx.xxx.xxx.xxx ~/myapp]$ docker-compose build
[ec2-user@xxx.xxx.xxx.xxx ~/myapp]$ docker-compose up -d
[ec2-user@xxx.xxx.xxx.xxx ~/myapp]$ docker-compose exec app bin/rails db:create db:migrate RAILS_ENV=production

Elastic IPアドレスにアクセスして正しく表示されれば完了です。

まとめ

AWSを使ってデプロイをすることは、初学者にはかなりハードルが高い内容だと思っておりましたが、素晴らしい文献等が豊富にあったため乗り越えることができました。
所々修正したり、試行錯誤しながらデプロイまで行ったので、全く同じやり方でできるかはわかりませんが、現場私ができる最適な方法だと考えております。

気になった点
参考記事によっては「この方法では開発環境で動いてしまうのでは?」「本番環境でないためRDSが使用されていないのではないか?」と思う部分もあり、いくつかの記事を参考にさせて頂きました。database.ymlのproduction:をRDSに指定したのであれば、本番環境でアプリケーションを立ち上げなければRDSは機能しないと考えております。(勘違いであれば申し訳ありません)
docker-composeの設定次第でなんとかできるのかもしれませんが、もう少しリサーチをしてみようと思いました。

課題
せっかくDockerを使用したのでAWSのECSやFargateを駆使してデプロイすることを考えるべきだったと思いました。
次の機会があれば挑戦したいと思います。

その他
私はS3も取り入れました。そちらは別記事にてまとめております。
AWS_S3+Ruby on Rails_Active Storageで画像データを保存

参考記事

無料!かつ最短?で Ruby on Rails on Docker on AWS のアプリを公開するぞ。
EC2上でRailsアプリケーションにDockerを導入する(Rails、Nginx、RDS)
見ながらやろう! AWSを始めよう -VPC構築編-
Rails5.2から追加された credentials.yml.enc のキホン

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

Amazon ECRにプライベートリポジトリを作成してイメージのpush/pullを実行する

1. はじめに

AWS re:Invent 2020で発表されましたが、Amazon ECRでパブリックレジストリが利用できるようになりました。
しかし、今回はそれとは関係なく、プライベートレジストリを使用します。
これまでECRを触ってこなかったので、使ってみたという内容です。
ecr005.png

2. 構成

2台のLinuxサーバを使用します。1台目からイメージをpushし、2台目はイメージをpullします。
ECRはリージョンサービスで、VPCエンドポイントも利用できます。(今回は使用しません)
ecr006.png

3. ECRの設定

リポジトリの作成

ECRのリポジトリを以下の設定で作成します。
可視性設定:プライベート
リポジトリ名:test-app-repo
タグのイミュータビリティ:無効
プッシュ時にスキャン:有効
KMS暗号化:有効
ecr003.png

4. EC2(1台目)からのpush

まず、ECRレジストリに対してDockerを認証します。「Login Succeeded」と表示されたことを確認します。
WARNINGが出ていますが、そのまま進めます。これについては本記事の「8. 警告&エラー集」で説明します。

$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com
WARNING! Your password will be stored unencrypted in /home/ec2-user/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

今回は「test-app」というイメージをpushしたいと思います。

$ docker images
REPOSITORY      TAG                 IMAGE ID            CREATED             SIZE
test-app        v1.0                72b199328340        10 days ago         461MB

docker tagコマンドでpushする対象にタグを設定します。
指定する形式は、「AWSアカウントID.dkr.ecr.リージョン.amazonaws.com/リポジトリ名:タグ」です。
タグを省略した場合は、自動でlatestのタグが付きます。

$ docker tag test-app:v1.0 \
> 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo:v1.0

タグ付けした結果を確認します。

$ docker images
REPOSITORY                                                        TAG                 IMAGE ID            CREATED             SIZE
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo   v1.0                72b199328340        10 days ago         461MB
test-app                                                          v1.0                72b199328340        10 days ago         461MB

では、イメージをpushします。

$ docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo:v1.0

コンソールから確認すると、イメージタグにv1.0が追加されたことが確認できます。
ecr007.png

5. EC2(2台目)からのpull

5-1. IAMポリシーの作成とアタッチ

2台目のEC2はaws configureで認証情報(アクセスキー、シークレットアクセスキー)を渡していないので、
そのままではECRにアクセスできません。
以下のIAMポリシーを作成してEC2のIAMロールにアタッチし、ECRにアクセスできるようにします。
IAMポリシー名:AmazonECRFullAccess

json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:*"
            ],
            "Resource": "*"
        }
    ]
}

5-2. EC2からのpull

まずは、1台目と同じようにECRレジストリに対してDockerを認証します。

$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com

イメージをpullします。

$ docker pull 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo:v1.0

結果を確認します。2台目のLinuxサーバがECRからイメージをpullすることができました。

$ docker images
REPOSITORY                                                        TAG                 IMAGE ID            CREATED             SIZE
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo   v1.0                72b199328340        10 days ago         461MB

6. v2.0をpushする

次に、タグ「v2.0」を付けたイメージもpushしてみたいと思います。

$ docker images
REPOSITORY                                                        TAG                 IMAGE ID            CREATED             SIZE
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo   v1.0                72b199328340        10 days ago         461MB
123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo   v2.0                72b199328340        10 days ago         461MB

イメージをpushします。

$ docker push 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo:v2.0

コンソールから確認すると、v2.0が追加されています。
rapture_20201218204702.png

7. イメージタグを削除する

v2.0が不要になったと仮定して、イメージタグを削除したいと思います。
(aws configureでregionを指定してある場合は、コマンドでは指定不要です)

$ aws ecr batch-delete-image --repository-name test-app-repo --image-ids imageTag=v2.0 --region ap-northeast-1
{
    "failures": [],
    "imageIds": [
        {
            "imageTag": "v2.0",
            "imageDigest": "sha256:58d3c26bee377e039c0ce5c2ef92ed2ce10b956bf3dc0cf5dba4b4d6f56aaf94"
        }
    ]
}

再度コンソールから確認すると、v2.0が削除されています。
ecr007.png
イメージを削除する場合は、イメージのダイジェストを指定すれば削除できます。
参考:https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/delete_image.html

8. 警告&エラー集

警告①

$ aws ecr get-login --region ap-northeast-1 --no-include-email
$ docker login -u AWS -p {認証トークン} https://123456789012.dkr.ecr.ap-northeast-1.amazonaws.com
WARNING! Using --password via the CLI is insecure. Use --password-stdin.

→AWS CLI バージョン 1.17.10 より前のバージョンを使用している場合はget-loginコマンドで認証しますが、
セキュリティリスクがあり非推奨です。AWS CLIのバージョンを上げて、get-login-passwordを使用することが推奨されます。
参考:https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/Registries.html

警告②

$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com
WARNING! Your password will be stored unencrypted in /home/ec2-user/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

→Dockerのデフォルトの動作として、ログインパスワードを暗号化せずにconfig.jsonに保存します。
外部のクレデンシャルストアに保存する方がより安全という警告です。
参考:https://docs.docker.com/engine/reference/commandline/login/#credentials-store

エラー①

$ docker pull 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/test-app-repo:v1.0
Error response from daemon: Get https://123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/v2/test-app-repo/manifests/v1.0: no basic auth credentials

→ECRレジストリに対してDockerを認証していないと出るエラーです。

エラー②

$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.ap-northeast-1.amazonaws.com
An error occurred (AccessDeniedException) when calling the GetAuthorizationToken operation: User: arn:aws:sts::123456789012:assumed-role/IAMロール名/インスタンスID is not authorized to perform: ecr:GetAuthorizationToken on resource: *
Error: Cannot perform an interactive login from a non TTY device

→aws configureで認証情報を指定していない、あるいはEC2のIAMロールにECRへのアクセスに必要な
IAMポリシー(本記事ではAmazonECRFullAccess)がアタッチされていない場合に出るエラーです。

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

ECRからdocker pullしてコンテナを起動して中身を確認する

Amazon ECRにDockerイメージを保存していて、それをAWS CodePipelineでFargateにデプロイするという構成において、デプロイに失敗した。コンテナがなにかおかしいらしいのでコンテナを確認したい。という状況になり、ECRからDockerイメージを落としてきて確認したくなったが、いつもやりかたを忘れるので備忘録として残しておく。

ECRからdocker pullする

$ docker pull your-aws-account-id.dkr.ecr.ap-northeast-1.amazonaws.com/xxx/yyy/zzz:latest

上記コマンドを実行すると認証エラーになった。(イメージのURLはAWSコンソールでECRを選択して選ぶ)

https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/Registries.html#registry_auth
ここを確認するとレジストリ認証が必要らしい。

$ aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin your-aws-account-id.dkr.ecr.ap-northeast-1.amazonaws.com

これでログインする。
aws cli v1ではget-login-passwordがなかったので注意。
事前に環境変数にAWS_ACCESS_KEY_IDとAWS_SECRET_ACCESS_KEYとAWS_SESSION_TOKENをセットする必要があるかも。

これが成功したら先程のdocker pullを再実行すると成功する。

docker pullしたイメージを起動する

$ docker images

まずは上記コマンドでイメージが追加されてることを確認する。

$ docker run -it your-aws-account-id.dkr.ecr.ap-northeast-1.amazonaws.com/xxx/yyy/zzz:latest /bin/bash

最後に /bin/bash と入れることでコンテナ内にbashで入れる。あとはご自由に。

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

sql-migrateを使ってみる

はじめに

この記事はITRC Advent Calendar 2020の18目の記事です。
前の記事?→ 【Neovim】琴葉葵が教えるおすすめのテキストエディタ【Voiceroid】
こんにちはRIN1208です。今回はsql-migrateを使ってみたら便利だったのでそのお話をしようかと思います。

必要環境

  • docker-compose
  • mac os

上記の環境で説明していきます

sql-migrateとは?

  • SQLite, PostgreSQL, MySQL, Oracleなどの色々なデータベースをサポートしている
  • CLIツールまたはライブラリとして使用可能
  • go getで取得可能
  • Go用のマイグレーションツール

構築する

リポジトリはこちら

今回sql-migrateを使用する上で必要なファイルは以下の4つです

  • dbconfig.yml
  • docker-compose.yml (docker-composeを使用して今回お話しするので)
  • Dockerfile   (go getでインストールするためgoの環境にしています)
  • sqlのマイグレーションファイル

docker-compose.ymlを書く

docker-compose.ymlを書いていきます。今回は確認用にphpmyadminを使用しています

version: '3.7'
services:
  api:
    build: .
    ports:
      - "8080:8080"
    tty: true
    volumes:
      - ./:/app
    working_dir: /app
    environment:
     - MYSQL_USER=root
     - MYSQL_PASSWORD=root
     - MYSQL_HOST=[mysql]
     - MYSQL_PORT=3306
     - MYSQL_DATABASE=test
  mysql:
    image: mysql:5.6
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=test
    command: >
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_general_ci
      --innodb_file_per_table
      --innodb_file_format=BARRACUDA
      --innodb_large_prefix=1
  phpmyadmin:
    image: phpmyadmin/phpmyadmin
    ports:
      - 8000:80
    environment:
      - PMA_HOST=mysql
      - PMA_PASSWORD=root
      - PMA_USER=root
      - PMA_ARBITRARY=1
    links:
      - mysql
    depends_on:
      - mysql

Dockerfileを書く

次にdockerfileを書いていきます

FROM golang:1.14

RUN go get github.com/rubenv/sql-migrate/...

sqlのマイグレーションファイルを書く

次にsqlのマイグレーションファイルを書きます。ここではsqlをそのまま書く為主キーや外部キーを簡単に設定できます。ファイル名は.sqlのファイルであればなんでも大丈夫です。

-- +migrate Up
CREATE TABLE IF NOT EXISTS user (
    user_id VARCHAR(128) NOT NULL PRIMARY KEY,
    user_name VARCHAR(128)

);
-- +migrate Down
DROP TABLE IF EXISTS user;

dbconfig.ymlを書く

次にdbconfig.ymlを書きます。ここではsql-migrateのconfigを書きます。

development:
    dialect: mysql 
    datasource: ${MYSQL_USER}:${MYSQL_PASSWORD}@tcp(${MYSQL_HOST}:${MYSQL_PORT})/${MYSQL_DATABASE}?parseTime=true
    dir: .
  • dialect
    この部分では使用するDBを選択しています。今回はmysqlを使用するのでmysqlと書いてあります。
  • datasource
    この部分ではmysqlに接続するための情報を記入しています。今回はそのまま書くのではなく環境変数から取得しています。環境変数はdocker-compose.ymlにて定義してあります。
  • dir
    この部分では実行するsqlファイルの場所を選択しています。/api/db下に置いてある場合はapi/dbと記入してください。

実行してみる

それでは以下のコマンドを実行してマイグレートをしてみましょう。

docker-compose exec api bash -c "sql-migrate up"

http://localhost:8000/ に接続しphpmyadminで確認無事userテーブルが作成できて入れば成功です。

終わりに

ここまで読んでくださりありがとうございます。
sql-migrateが便利だったので今回記事に書きました。
sql-migrateを使おうとしている方の手助けになれば幸いです。
また間違っている点などがございましたらコメントなどで指摘していただけると助かります。

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

io_uringを使うプログラムはCentOS 8上のDockerで動かない

Linux kernel 5.1から導入されたio_uringという非同期IOのカーネル機能がありますが、それを使うDockerイメージはCentOS 8で動きませんよと。
知ってる人にはまあ、そうだよねという事ではあるのですが。

Docker/Linuxコンテナのポータビリティは万能ではないんですよと議論したい場合の論拠として。

io_uring使うプログラムをUbuntu 20.10で作る

1.OSがUbuntu 20.10の仮想マシンを作る。
https://ubuntu.com/download

2.Dockerをインストールする。
https://docs.docker.com/engine/install/ubuntu/

3.Docker上でUbuntu 20.10イメージを起動する。
# docker run -it --rm --name=io_uring-test ubuntu:20.10 bash

4.一応、uname -aで利用中のカーネルを確認。
(c)# uname -a

(実行結果)
root@17003dd74a2f:/liburing/examples# uname -a
Linux 17003dd74a2f 5.8.0-33-generic #36-Ubuntu SMP Wed Dec 9 09:14:40 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

5.gccとio_uringのライブラリ、gitをインストールする。
(c)# apt-get update
(c)# apt-get install -y build-essential liburing-dev git

6.io_uringのサンプルプログラムを入手する。
https://blogs.oracle.com/linux/an-introduction-to-the-io_uring-asynchronous-io-framework
(c)# git clone https://github.com/axboe/liburing.git

7.サンプルプログラムをコンパイルする。
(c)# cd liburing/examples
(c)# gcc -Wall -O2 -D_GNU_SOURCE -o io_uring-test io_uring-test.c -luring

8.プログラムを実行する。当然、こちらは動作する。
(c)# ./io_uring-test io_uring-test.c

(実行結果)
root@08ad6f4c804c:/liburing/examples# ./io_uring-test io_uring-test.c
Submitted=1, completed=1, bytes=2256

9.コンテナからデタッチ(C-p, C-q)し、コミット、イメージ保存する。
# docker commit io_uring-test io_uring-test
# docker save io_uring-test -o io_uring-test.tar

CentOS 8のDockerでそのプログラムを動かす

1.OSがCentOS 8.3の仮想マシンを作る。
https://www.centos.org/download/

2.Dockerをインストールする。
https://docs.docker.com/engine/install/centos/

3.先のDockerイメージ(io_uring-test.tar)をCentOS 8マシンにコピーし、ロードする。
# docker load -i io_uring-test.tar

4.コンテナを起動する。
# docker run -it --rm io_uring-test bash

5.一応、uname -aで利用中のカーネルを確認。ホストのCentOS 8と同じ4.18なはず。
(c)# uname -a

(実行結果)
root@824c737193b6:/# uname -a
Linux 824c737193b6 4.18.0-240.1.1.el8_3.x86_64 #1 SMP Thu Nov 19 17:20:08 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

(ついでに)
root@824c737193b6:/liburing/examples# cat /etc/os-release
NAME="Ubuntu"
VERSION="20.10 (Groovy Gorilla)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.10"
VERSION_ID="20.10"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=groovy
UBUNTU_CODENAME=groovy

5.サンプルプログラムを動かす。
(c)# cd liburing/examples/
(c)# ./io_uring-test io_uring-test.c

(実行結果)
root@824c737193b6:/liburing/examples# ./io_uring-test io_uring-test.c
queue_init: Function not implemented

まあ、動きませんよね、と。

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

io_uringを使うプログラムはCentOS 8上のDockerでは動かない

Linux kernel 5.1から導入されたio_uringという非同期IOのカーネル機能がありますが、それを使うDockerイメージはCentOS 8で動きませんよと。
知ってる人にはまあ、そうだよねという事ではあるのですが。

Docker/Linuxコンテナのポータビリティは万能ではないんですよと議論したい場合の論拠として。

io_uring使うプログラムをUbuntu 20.10で作る

1.OSがUbuntu 20.10の仮想マシンを作る。
https://ubuntu.com/download

2.Dockerをインストールする。
https://docs.docker.com/engine/install/ubuntu/

3.Docker上でUbuntu 20.10イメージを起動する。
# docker run -it --rm --name=io_uring-test ubuntu:20.10 bash

4.一応、uname -aで利用中のカーネルを確認。
(c)# uname -a

(実行結果)
root@17003dd74a2f:/liburing/examples# uname -a
Linux 17003dd74a2f 5.8.0-33-generic #36-Ubuntu SMP Wed Dec 9 09:14:40 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

5.gccとio_uringのライブラリ、gitをインストールする。
(c)# apt-get update
(c)# apt-get install -y build-essential liburing-dev git

6.io_uringのサンプルプログラムを入手する。
https://blogs.oracle.com/linux/an-introduction-to-the-io_uring-asynchronous-io-framework
(c)# git clone https://github.com/axboe/liburing.git

7.サンプルプログラムをコンパイルする。
(c)# cd liburing/examples
(c)# gcc -Wall -O2 -D_GNU_SOURCE -o io_uring-test io_uring-test.c -luring

8.プログラムを実行する。当然、こちらは動作する。
(c)# ./io_uring-test io_uring-test.c

(実行結果)
root@08ad6f4c804c:/liburing/examples# ./io_uring-test io_uring-test.c
Submitted=1, completed=1, bytes=2256

9.コンテナからデタッチ(C-p, C-q)し、コミット、イメージ保存する。
# docker commit io_uring-test io_uring-test
# docker save io_uring-test -o io_uring-test.tar

CentOS 8のDockerでそのプログラムを動かす

1.OSがCentOS 8.3の仮想マシンを作る。
https://www.centos.org/download/

2.Dockerをインストールする。
https://docs.docker.com/engine/install/centos/

3.先のDockerイメージ(io_uring-test.tar)をCentOS 8マシンにコピーし、ロードする。
# docker load -i io_uring-test.tar

4.コンテナを起動する。
# docker run -it --rm io_uring-test bash

5.一応、uname -aで利用中のカーネルを確認。ホストのCentOS 8と同じ4.18なはず。
(c)# uname -a

(実行結果)
root@824c737193b6:/# uname -a
Linux 824c737193b6 4.18.0-240.1.1.el8_3.x86_64 #1 SMP Thu Nov 19 17:20:08 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

(ついでに)
root@824c737193b6:/liburing/examples# cat /etc/os-release
NAME="Ubuntu"
VERSION="20.10 (Groovy Gorilla)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.10"
VERSION_ID="20.10"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=groovy
UBUNTU_CODENAME=groovy

5.サンプルプログラムを動かす。
(c)# cd liburing/examples/
(c)# ./io_uring-test io_uring-test.c

(実行結果)
root@824c737193b6:/liburing/examples# ./io_uring-test io_uring-test.c
queue_init: Function not implemented

まあ、動きませんよね、と。

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

Docker+Prometheusで外形(URL)監視を作る

初のAdvent calendarは最近触ってみたPrometheusという監視ツールの構築について書きます
みなさん、Webサイトの死活監視はされていますでしょうか?
「自分で構築できるの?」「SaaSと契約するほど大きなシステムじゃないんだけど・・・」「サーバを1から立てるのは辛い」などなど、私もハードルが高い機能の1つだと思っていました
が、DockerとPrometheusを組み合わせることで意外と簡単に外形監視の仕組みを作ることができるので、書いていこうと思います

外形(URL)監視とは何か?

外形監視とは、WebサイトやAPIサーバが正常に動いているか?をHTTPアクセスで確認する監視方法です
「レスポンスが正常か?」「規定の秒数以内にレスポンスが返却されるか?」などを確認します
良いところとしては、ユーザと同じ方法でアクセスするため、ネットワークを含めてシステムまたはAPI全体の正常/異常を確認することが可能です
サーバのリソース(CPUやメモリなど)を内部から監視する方法と組み合わせて使うことが多いと思います
AWSのサービスを使っていますが、簡単に説明した図になります

スクリーンショット 2020-12-18 8.07.35.png

背景

  • Webシステムに対して外形監視をしたい
  • SaaSもあるがシステムが大規模じゃない場合はオーバースペックだと感じた(大規模ならお金かけて使った方が良いのかもしれないけれど)
  • 柔軟な選択ができるよう環境(開発端末・クラウドなど)に関係なく構築できるようにしたい

今回やること

  • 監視ツールであるPrometheusを使って外形監視をする
  • OSに寄らずに環境構築できるDocker+Prometheusで構築する
  • 開発端末で起動する
  • 異常を検知した場合、Slackに通知する

説明しないこと

ここでは書かないので、調べてみてください...

  • ターミナルの操作方法
  • Docker, docker-composeについて

環境

今回はMacでやりますが、Dockerを使っているので、windowsでもlinuxでも起動できます

  • Mac : 10.15.5
  • Docker : 19.03.8
  • docker-compose : 1.25.5

使用したDockerイメージ

  • prom/prometheus : 2.19.1
  • prom/blackbox-exporter : 0.17.0
  • prom/alertmanager : 0.21.0

フォルダ・ファイル構成

━ docker-compose.yml
┣ prometheus
┃  ┗ alert_roles.yml
┃  ┗ prometheus.yml
┣ blackbox_exporter
┃  ┗ config.yml
┗ alertmanager
  ┗ config.yml

docker-compose.ymlの作成

  • prometheus:本体のイメージ
  • blackbox_exporter:URL監視してくれるexporter(外部ライブラリ的なもの)
  • alertmanager:アラートが発生した時にメッセージ通知をしてくれるexporter(今回はslack通知で使用する)
  • 各々のポート番号とconfigファイルを設定していきます
docker-compose.yml
version: '3'
services:
  prometheus:
    image: prom/prometheus
    container_name: prometheus
    volumes:
      - ./prometheus:/etc/prometheus
    command: "--config.file=/etc/prometheus/prometheus.yaml"
    ports:
      - 9090:9090
    restart: always
  blackbox_exporter:
    image: prom/blackbox-exporter:latest
    volumes:
      - ./blackbox_exporter/config.yml:/etc/blackbox_exporter/config.yml
  alertmanager:
    image: prom/alertmanager
    container_name: alertmanager
    volumes:
      - ./alertmanager:/etc/alertmanager
    command: "--config.file=/etc/alertmanager/config.yaml"
    ports:
      - 9093:9093
    restart: always

blackbox_exporter

URL監視の設定をyml形式で記載していきます
modules:には確認したいプロトコルごとに設定を作っていきます(tcp、pop3、sshもデフォルトで用意されています)
今回はPOSTメソッドの設定としてhttp_post_2xx:を追加しています
headers:にはHTTPヘッダを設定することができます
設定できる内容についてはblackbox_exporterのConfigurationを参照してください

blackbox_exporter/config.yml
modules:
  http_2xx:
    prober: http
    http:
  http_post_2xx:
    prober: http
    http:
      method: POST
      headers:
        xxx: yyyy

prometheus

prometheus本体で外形監視の設定を記載します
評価内容は``alert_roles.yml''に定義しています

prometheus/prometheus.yml
global:
  # prometheusがexporter等に情報を取りに行く間隔(今回はblackbox_exporter)
  scrape_interval:     15s 
  # ruleの評価を行う間隔(今回はrule_filesで指定されているalert_roles.ymlが評価内容)
  evaluation_interval: 15s 
  external_labels:
      monitor: 'codelab-monitor'

rule_files:
  - /etc/prometheus/alert_roles.yml

alerting:
  alertmanagers:
    - scheme: http
      static_configs:
      - targets:
        - alertmanager:9093

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets:
        - prometheus:9090
  # 1つの監視条件をjobという単位で扱う
  - job_name: 'blackbox_http'
    metrics_path: /probe
    # blackbox_exporterのconfig.ymlで定義しているmoduleを指定
    params:
      module: [http_post_2xx]
    static_configs:
      # 監視対象のURLを指定
      - targets:
        - '[target_url]'
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: blackbox_exporter:9115
alert_roles.yml
# alertの定義
groups:
- name: blackbox_exporter
  rules:
  - alert: http_success
    # 評価するメトリクスと条件
    # probe_successの条件を"blackbox_http"のjobに適用しています
    expr: probe_success{job='blackbox_http'} != 1
    # 評価NGとするまでの継続時間(10秒間alert状態の場合NG)
    for: 10s
    labels:
      severity: critical
    annotations:
      summary: "{{ $labels.instance }}: http request not return 200"
      description: "{{ $labels.instance }} http request not return 200 for more than 10 seconds."

alertmanager

alertmaneagerは通知を行います
今回はslackへの通知を設定しています
slackのwebhookは公式を参照ください

config.tml
global:
  # slackのwebhookURLを指定
  slack_api_url: '[slack webhook url]'
  smtp_smarthost: 'localhost:25'
  smtp_require_tls: false
  smtp_from: 'Alertmanager'

route:
  receiver: 'test-route'
  # グループ化の設定(アラート名)
  group_by: '[alertname]'
  # alertグループの通知の送信を最初に待機する時間
  group_wait: 10s
  # alertグループでの最小送信間隔(新しいアラート送信まで待機する時間)
  group_interval: 5m
  # 通知を再度送信するまで待機する時間
  repeat_interval: 1h

receivers:
- name: 'test-route'
  # slackのチャンネル名
  slack_configs:
  - channel: '#general'
  # email(※slackには表示されなかった)
  email_configs:
  - to: "zzz@gmail.com"

dockerコンテナ起動

dockerコンテナを起動します
今回は複数コンテナを一度で上げるのにdocker-composeを使用します

$ docker-compose build
# "-d"オプションをつけることで、バックグラウンドで実行します
# オプションがないとターミナルを閉じた時にコンテナが停止してしまいます
$ docker-compose up -d

# コンテナの起動を確認
$ docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                    NAMES
ab4455256cff        prom/prometheus                 "/bin/prometheus --c…"   5 days ago          Up 5 days           0.0.0.0:9090->9090/tcp   prometheus
830bf6475888        prom/alertmanager               "/bin/alertmanager -…"   5 days ago          Up 5 days           0.0.0.0:9093->9093/tcp   alertmanager
b6fcd4f26f57        prom/blackbox-exporter:latest   "/bin/blackbox_expor…"   5 days ago          Up 5 days           9115/tcp                 prometheus_sample_blackbox_exporter_1

Prometheusのダッシュボードを確認

http://localhost:9090にアクセスする
実際の運用ではhttps、ポートフォワーディングなどに対応しますが、今回は開発端末なのでそのままにします
alert_roles.ymlで指定した評価メトリクスを入力し、executeをクリックすると評価結果をグラフで表示できます
今回はhttpリクエストが成功(200 OK)を評価していて、1.0であれば正常となります

スクリーンショット 2020-12-18 20.36.04.png

メニューからAlertを選択するとアラート(通知)の状態を確認することができます
状況が色分けされていて、一目でどの評価がエラーとなっているか確認ができます

スクリーンショット 2020-12-18 20.53.45.png

slack通知を確認する

監視対象のURLをありえないURLに変更して、httpレスポンスが500系を返却するようにしてAlertの確認をします
httpリクエストが異常を返却するとAlertメニューの状況が赤く変化します

スクリーンショット 2020-12-18 21.03.11.png

そして、slackにエラー発生していることが通知されます

スクリーンショット 2020-12-18 21.10.26.png

今回はSlackというチャットサービスでしたが、チャットの通知に反応する習慣がない人などから「Slackに通知すると気づきにくい!
もっと早く確実に気づきたい」という要望があれば、SaaSの電話コールサービスと繋げることでAlert発生時に電話をコールすることも可能です
通知することが大事ではなく、人間が認識する方法・可能性を考慮した設計にすることが大事だと思っています

おまけ

Prometheusの見た目は正直質素・・・だと思います(必要な機能は揃っているので十分な内容です)が、
「デザインがイケてるダッシュボードにしたい!」という方は、Grafanaと連携させるとかっこよくなると思います
Prometheusと同様にDockerイメージがあるので、docker-compose.ymlに追加することでGrafanaが起動します
興味がある方はぜひチャレンジしてみてはいかがでしょうか

スクリーンショット 2020-12-18 21.23.08.png
(画像は公式のデモになります)

「監視を構築するのはかなり辛いなぁ・・・」という方は、
簡単に構築して設定をコード管理できるDocker+Prometheusで監視機能を構築してクリスマスを迎えてはいかがでしょうか?

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

Docker環境にMySQLを構築してDBを取り込む

概要

Docker環境にMySQLを構築し、SQLデータを流し込む

前提

Dockerがインストールされている状態

ディレクトリ構成

db_sample/
  ├ docker/
  |   └ mysql/
  |        ├ conf.d/
  |        |     └ my.cnf
  |        ├ initdb.d/
  |              └ xxxxxx.sql
  |        └ Dockerfile
  └ docker-compose.yml              

ファイルの準備

docker-compose.yml作成

db_sample/docker-compose.yml
version: '3.3'
services:
  db:
    build: ./docker/mysql       # Dockerfileの置き場所を指定
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: sample_db
      MYSQL_USER: user
      MYSQL_PASSWORD: password
      MYSQL_ROOT_PASSWORD: rootpassword
    ports:
      - "3314:3306"
    volumes:
      - ./docker/mysql/initdb.d:/docker-entrypoint-initdb.d
      - ./docker/mysql/conf.d:/etc/mysql/conf.d
      - ./log/mysql:/var/log/mysql

Dockerfile作成

db_sample/docker/mysql/Dockerfile

FROM mysql:5.7
RUN touch /var/log/mysql/mysqld.log

my.conf作成

db_sample/docker/mysql/conf.d/my.conf
[mysqld]
character-set-server=utf8
explicit-defaults-for-timestamp=1
general-log=1
general-log-file=/var/log/mysql/mysqld.log

[client]
default-character-set=utf8

SQLファイルの配置

db_sample/docker/mysql/initdb.d/配下に置く

Dockerコマンド実行

db_sampleディレクトリの配下に移動

$ cd /../db_sample

docker-compose up -dの実行

$ docker-compose up -d
Creating network "db_sample_default" with the default driver
Building db
Step 1/2 : FROM mysql:5.7
5.7: Pulling from library/mysql
6ec7b7d162b2: Pull complete
fedd960d3481: Pull complete
7ab947313861: Pull complete
64f92f19e638: Pull complete
3e80b17bff96: Pull complete
014e976799f9: Pull complete
59ae84fee1b3: Pull complete
7d1da2a18e2e: Pull complete
301a28b700b9: Pull complete
979b389fc71f: Pull complete
403f729b1bad: Pull complete
Digest: sha256:d4ca82cee68dce98aa72a1c48b5ef5ce9f1538265831132187871b78e768aed1
Status: Downloaded newer image for mysql:5.7
 ---> 697daaecf703
Step 2/2 : RUN touch /var/log/mysql/mysqld.log # 指定の場所にログを記録するファイルを作る
 ---> Running in 7fe949f8a39f
Removing intermediate container 7fe949f8a39f
 ---> f6323d72a74c
:
:
Successfully built f6323d72a74c
Successfully tagged mysql:5.7
WARNING: Image for service db was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Creating db_sample_db_1 ... done

Creating db_sample_db_1 ... doneが表示されたら、作成完了

コンテナ起動確認

docker-compose ps の実行

$ docker-compose ps
      Name               Command          State          Ports
----------------------------------------------------------------------
db_sample_db_1   docker-entrypoint.sh   Up      0.0.0.0:3314->3306/t
                   mysqld                         cp, 33060/tcp

コンテナ内のDB接続

コンテナ内にアクセス

$ docker exec -it db_sample_db_1 bash
root@55c55b394991:/#

MySQL内に入る
パスワードはdocker-compose.ymlのMYSQL_PASSWORDを指定

root@55c55b394991:/# mysql -u user -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 3
Server version: 5.7.32-log MySQL Community Server (GPL)

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

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

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

mysql>

MySQLでDB選択とテーブル確認

使用するDBにsample_dbを選択後、テーブル一覧を表示する

mysql> use sample_db
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed

# テーブル表示
mysql> show tables;
+------------------------------------------+
| Tables_in_sample_db                      |
+------------------------------------------+
| table_01                                 |
| table_02                                 |
:                                          |
:                                          |
| table_nn                                 |
+------------------------------------------+
nn rows in set (0.01 sec)

データ確認

mysql> select * from table_01;

# table_01のリストが表示される

環境削除

コンテナの停止とネットワークの削除

$ docker-compose down
Stopping db_sample_db_1 ... done
Removing db_sample_db_1 ... done
Removing network db_sample_default
$

dockerイメージ削除
tagが5.7のとの2つが作られているのでIMAGE IDを指定して両方削除

$ docker images
REPOSITORY                 TAG                  IMAGE ID       CREATED         SIZE
mysql                      5.7                  f6323d72a74c   6 hours ago     448MB
mysql                      <none>               697daaecf703   6 days ago      448MB
:
:

$ docker rmi f6323d72a74c
Untagged: mysql:5.7
Deleted: sha256:49....
Deleted: sha256:49....
:
$ docker rmi 697daaecf703
Untagged: mysql@sha256:d4...
Deleted: sha256:697d...
Deleted: sha256:521...

さいごに

今回は、Docker環境のコンテナにMySQLを構築し、指定場所にあるSQLファイルを実行してテーブル、データ情報を取り込んでみました。

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

[WIP]Docker+Streama+NFSの構成を試してみた

初めに

年末に改めて書くので許してください。。。

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

[WIP]DockerのVolumeにNFSを利用する

初めに

年末に改めて書くので許してください。。。

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

Dockerについて

Dockerとは

「コンテナ技術」を用いた仮想環境を構築するツール。
Docker社が開発した、オープンソースの人気 No.1ソフトウェア
1つのコンテナとして確立させる為の手間をまとめてるので簡単にコンテナが作れちゃう。

 

Dockerの仕組み

  • DockerHub      に保存してある
  • Dockerイメージ   (コンテナ作る為のレシピ)を使い
  • Dockerコンテナ    を作って
  • Dockerエンジン    で動かします。  

DockerHub ( レジストリ )

Dockerの為のコンテナ共有サービス。ほぼ GitHub 。
① Dockerのイメージがたくさん転がっているので、そこからPullしてコンテナを作ります。( Pullしたイメージを元にrunコマンドでコンテナを作成 )
② 作ったコンテナで開発や作業をし、それをイメージにcommitする。 
③ コミットしたイメージをDockerHubにPushする事で自分のリポジトリにアップロード。
④ 開発作業などで違うPCでもイメージを使いたいときに、そのアップロードしたイメージをPullするだけでOK!
 
image.png

Dockerイメージ

コンテナの元となるもの、ひな型、パッケージ。
イメージはいくつかのレイヤと呼ばれるファイルを重ねることで出来ています。
もし欲しいイメージが無かった場合はDockerfileを使い自分でイメージを作ることが出来ます。

FROM  ubuntu:18.10       #ベースとなるOSの指定    

LABEL version="1.0"        #Dockerfileのメタ情報(こう言うFileだよと言う情報)
LABEL description="Dockerfileのテスト、Apacheサーバー"

RUN   apt-get update
RUN   apt-get install -y apache2   #このFileに入るレイヤのインストール

CMD   ["apachectl", "-D", "FOREGROUND"]  #コマンドで上のRUNを起動させている

 

コマンド  実行内容 
FROM ベース(親)画像を指定します。
LABEL メタデータを提供します。 メンテナ情報を含めるのに良い場所です。
ENV 永続的な環境変数を設定します。
RUN コマンドを実行してイメージレイヤを作成します。 パッケージをコンテナにインストールするために使用されます。
COPY ファイルとディレクトリをコンテナにコピーします。
ADD ファイルとディレクトリをコンテナにコピーします。 ローカルの.tarファイルをアンパックできます。
CMD 実行中のコンテナにコマンドと引数を提供します。 パラメータは上書きできます。 CMDは1つだけです。
WORKDIR あとに続く説明の作業ディレクトリを設定します。
ARG ビルド時にDockerに渡す変数を定義します。
ENTRYPOINT 実行中のコンテナにコマンドと引数を提供します。 引数は存続します。
EXPOSE ポートを公開します。
VOLUME 永続データにアクセスして保存するためのディレクトリマウントポイントを作成します。

Dockerコンテナ

Dockerイメージの情報を元に起動された仮想環境

Dockerエンジン

Dockerの心臓、ここがあってのDockerであり、Dockerそのものになります。
コンテナやイメージからくるコマンドをホストOSに伝えて動かす為のもの。

3つの要素からなりたっており

•  コマンド命令を受け付ける部分
•  REST API(ステートレスなデータのやり取り)
•  Dockerデーモン(ホストOSとやり取りするところ)
                           と分かれています。

 image.png

まとめ

これだけ簡単に環境設定が出来て軽くて使い勝手が良いなんて三拍子揃ってるなんて素敵!!
デメリットも色々あるようですが、気軽に使えるから便利!!!
 

参考

http://docs.docker.jp/v1.12/engine/understanding-docker.html
https://qiita.com/shubatto/items/105f5b90e1cd91ba7c4c
https://blog.codecamp.jp/docker-file-how-to
https://tech-lab.sios.jp/archives/19073
https://knowledge.sakura.ad.jp/13265/
https://www.youtube.com/watch?v=VIzLh4BgKck

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

Docker環境でMySQLのログを確認する

まず、dockerのMySQLコンテナに入ります。
MySQLサーバにログインして、以下のようにgeneral_logの位置を確認します。

mysql> show variables like 'general_log%';
+------------------+---------------------------------+
| Variable_name    | Value                           |
+------------------+---------------------------------+
| general_log      | OFF                             |
| general_log_file | /var/lib/mysql/55ca40b8744.log |
+------------------+---------------------------------+
2 rows in set (0.00 sec)

OFFになっているので、ONにします。
こうしないとファイルが出現しないようです。

mysql> set global general_log = on;
Query OK, 0 rows affected (0.01 sec)

MySQLからぬけて、var/lib/mysqlに移動します。ここのファイルの内容を参照すれば見れます。

root@55ca40b8744e:~# cd /var/lib/mysql
root@55ca40b8744e:/var/lib/mysql# cat 55ca40b8744.log 
Tcp port: 3306  Unix socket: /var/run/mysqld/mysqld.sock
Time                 Id Command    Argument
2020-12-18T17:18:27.044729+09:00       26 Quit

先ほど MySQLのサーバを抜けたので、Quitしたと出ています。

試しにdeleteしたときのログは以下のように出ます。

2020-12-18T17:02:09.716428+09:00       67 Prepare   DELETE FROM `TABLE` WHERE `table`.`id` = ?
2020-12-18T17:02:09.716513+09:00       67 Execute   DELETE FROM `TABLE` WHERE `table`.`id` = 0
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker Desktopをupdateしたらコンテナを起動できなくなった話

今まで、dockerのアップデートを忘れていたのですが、久々にアップデートしてみたら、アップデート後、docker-compose upで以下の様なエラーが発生。その時の解決策です。

ERROR: for node  Cannot start service node: Mounts denied: approving /Users/ryota/Library/Mobile Documents/com~apple~CloudDocs/path/to/file: file does not exist
ERROR: Encountered errors while bringing up the project.

解決した方法

スクリーンショット 2020-12-18 15.27.57.png

上記画像の通り、Docker DesktopのPreferencesを開いた後に、Experimental Featuresのタブを選択して、Use gRPC FUSE for file sharingOFFにすれば上手くいきました?

ちなみに、バージョンは3.0.1でした。

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

Pleasanter NetCore をDockerで上げる

はじめに

国産OSSとして有名なPleasanterですが、前々から興味があったので、試してみました。

が、セットアップ手順がとても難しく、
簡単に立ち上げられて簡単に壊せる環境が作りたかったので docker-compose で上がるようにしてみました。

なお、本記事は私が学習目的で実施した内容で、Pleasanter公式の手順ではない旨ご了承ください。
あと、コメントなどの画像投稿機能が動いていません(ファイルアップロードは動く)。そこら辺分かり次第修正します。

実施環境

Windows 10 64bit 上の docker(WSL2) と、
Ubuntu 18.04 64bit 上の docker で動作することを確認しました。

コード

https://github.com/yoh1496/Implem.Pleasanter.NetCore/tree/feature/docker

ここに上げてます。

手順

下記手順は上記ブランチをチェックアウトしてから行うのを前提とします。

git clone https://github.com/yoh1496/Implem.Pleasanter.NetCore.git
cd Implem.Pleasanter.NetCore
git checkout feature/docker

起動

下記コマンドでバックグラウンドに起動できます。

docker-compose up -d

セットアップ

Pleasanterのドキュメントにある CodeDefiner コマンドは下記コマンドで代替できます。

docker-compose exec pleasanter dotnet Implem.CodeDefiner.NetCore.dll <args>

ブラウザで開く

デフォルトでは 5001 番ポートで開けます。

image.png

簡単?

解説

ちょっと備忘録的にDockerfileを書くにあたり検討した内容を記載します。

マルチステージビルド

# 冒頭
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS base
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
# 末尾
FROM build AS publish
RUN dotnet publish "Implem.Pleasanter.NetCore.sln" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .

今回はこんな感じで「マルチステージビルド」というものをしています。
こうすることで、出来上がるイメージには SDK が含まれず軽いイメージができあがります。

設定ファイルの分離

    volumes:
      - ./Implem.Pleasanter/App_Data/:/app/App_Data/

docker-compose.yml 内で上記のように App_Data を外出しできるようにしています。「とりあえず」でやってしまったので今後要検証です。

永続化?

Pleasanterのデータ保持がどのようになされているのか、まだ理解しきれていないので特に手はつけていません。

postgreSQL を別コンテナに

App_Data のところ ConnectionString が localhost でベタ書きされていたので、postgres でベタ書きしました(よくない)

{
    // 略
    "SaConnectionString": "Server=postgres;Database=postgres;UID=postgres;PWD=SetSaPWD",
    "OwnerConnectionString": "Server=postgres;Database=#ServiceName#;UID=#ServiceName#_Owner;PWD=SetAdminsPWD",
    "UserConnectionString": "Server=postgres;Database=#ServiceName#;UID=#ServiceName#_User;PWD=SetUsersPWD",
    // 略
}

大文字小文字問題

あまり意図がわかっていなくて恐縮ですが、

  • wwwroot/images フォルダに Hayato*.png と、 hayato*.png というファイル
  • dotnet publish では それらは同一ファイルとしてみなされ 小文字のhayato*.png がコピーされない
  • トップページでは hayato*.png を参照する

というコンボで404が発生してしまったため Hayato*.png を消しています。

https://github.com/Implem/Implem.Pleasanter.NetCore/tree/master/Implem.Pleasanter/wwwroot/images

終わりに

.Net Framework 依存のコードが Implem.Pleasanter 内にあるため、
ビルド時に大量にWarningが発生しますが、手元で動かしている分には普通に動いているようです。
(コメントの画像投稿機能は除く)

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

Serverless FrameworkでLambdaコンテナイメージを利用する

こちらは、AWS LambdaとServerless Advent Calendar 2020 25日目の記事になります!

クリスマスの公開ですが季節感はないです
悪しからず?

はじめに

AWS re:Invent 2020にてLambdaのコンテナイメージのサポートが発表されましたが、
我らが愛するServerless Frameworkでも早々にサポートが行われたので、お試しで使ってみました?

serverless.yml における定義については、こちらのブログにある通り、 <account>.dkr.ecr.<region>.amazonaws.com/<repository>@<digest> の形式で指定する必要があるそうです
タグでなく、イメージのダイジェストで指定する必要があるとのことなので、 sls deploy 時にいい感じに注入する必要があります?

作ったもの

以下で公開しています?
https://github.com/yktakaha4/lambda-docker-serverless

なるべく簡単に動作を試せるように、
環境構築からデプロイまでに必要なもろもろをGitHub Actionsにまとめてます
変更すべき箇所はREADMEにまとめていますので併せてご覧ください

ポイント

Dockerファイルは、 public.ecr.aws/lambda/xxxxx から作成する必要があるそうです
こちらにてベースイメージが公開されています?

あと、従来は serverless.yml にて関数のエントリーポイントを設定していたものと思いますが、Dockerfileにて設定しておく必要があるようです
個人的に、ECSのScheduled Taskで単一のコンテナに複数の関数を含めて、定義ごとに動かすものを変えるということをやっていたのですが、現状だと個別にビルドしておく必要がある感じなのでしょうか...?

Dockerfile
FROM public.ecr.aws/lambda/nodejs:12 AS builder

WORKDIR /opt/build

COPY . .

RUN npm ci

RUN npm run build

##### ##### ##### #####
FROM public.ecr.aws/lambda/nodejs:12 AS runner

COPY --from=builder \
  /opt/build/package*.json \
  ./

COPY --from=builder \
  /opt/build/dist \
  ./dist

RUN npm ci --only=production

# !!! ここポイント !!!
CMD ["dist/index.handler"]

イメージのビルドとECRへのプッシュが済んだら、イメージのダイジェストを取得し、 sls コマンドに渡せるように環境変数に設定します
従来の set-env は現在無効となっているので、新しい書き方でやってます

あと、今回初めて知ったのですが、GitHub Actionsの環境にはデフォルトで aws コマンドがインストールされてるんですね...!

deployment.yml(抜粋)
jobs:
  deploy:
    runs-on: ubuntu-18.04
    timeout-minutes: 300

    steps:
      # 略

      # ECR
      - uses: aws-actions/amazon-ecr-login@v1
        id: login-ecr

      - run: |
          docker build -t $REGISTRY/$REPOSITORY:$TAG .
          docker push $REGISTRY/$REPOSITORY:$TAG

          # !!! ここポイント !!!
          echo "IMAGE_DIGEST=$(aws ecr describe-images --repository-name $REPOSITORY --image-ids imageTag=$TAG --output text --query 'imageDetails[0].imageDigest')" >> $GITHUB_ENV
        env:
          REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          REPOSITORY: lambda-docker-serverless-repos
          TAG: latest

      # Serverless Framework
      - run: npm ci

      - run: npm run deploy
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
          IMAGE_DIGEST: ${{ env.IMAGE_DIGEST }}

serverless.yml では、従来 handler を使っていたところを、 image でコンテナを指定します
#{AWS::AccountId} など、シャープで始まるものは serverless-pseudo-parametersの働きにより実値が埋め込まれます

serverless.yml
service: lambda-docker-serverless

provider:
  name: aws
  stage: prod
  region: ${env:AWS_DEFAULT_REGION}
  deploymentBucket: lambda-docker-serverless-deployment

functions:
  index:
    # !!! ここポイント !!!
    image: "#{AWS::AccountId}.dkr.ecr.#{AWS::Region}.amazonaws.com/lambda-docker-serverless-repos@${env:IMAGE_DIGEST}"
    events:
      - http:
          path: index
          method: post
          cors: true

plugins:
  - serverless-pseudo-parameters

今回は、こんなシンプルな関数を作ってみました
リクエストで受け取った名前を大文字にして、挨拶を返す処理になります?

index.ts
import { APIGatewayProxyHandler } from "aws-lambda";
import "source-map-support/register";

interface Request {
  name?: string;
}

export const handler: APIGatewayProxyHandler = async (event) => {
  try {
    const { name } = JSON.parse(event.body ?? "{}") as Request;

    return {
      statusCode: 200,
      body: JSON.stringify({
        message: `Hello, ${(name ?? "nanashi-san").toUpperCase()} !`,
      }),
    };
  } catch (e) {
    return {
      statusCode: 500,
      body: JSON.stringify({
        error: String(e),
      }),
    };
  }
};

https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/index にアクセスしてみます
Insomniaで実行してみると、ちゃんと動いてそうでいい感じです!

insomnia.png

おわりに

当初は、関数内でPuppeteerを動かそうと少し試していたのですが、
従来の一番安定したやり方だったchrome-aws-lambdaを使うよりも楽に構築できると思いきや、ライブラリの不足やディレクトリの権限周りの問題で結構留意することが多かったので諦めました...
(ちなその残骸はこちらにあります⚰️)

従来実行環境の微妙な差異に悩まされることもちょいちょいあったように思いますが、
今後コンテナベースの環境で開発ができるようになると利便性が上がるので、引き続き動向を追っていきたいですね????

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