20201027のdockerに関する記事は6件です。

datadogでdocker-composeを使ってnginxを監視する方法

Datadogでnginxを監視する

有償の監視ツールdatadogでnginxを監視する方法。
ただし、datadogのagentはdocker-composeでセットアップする場合・・

公式ドキュメント(ほぼ役に立たない)
https://docs.datadoghq.com/ja/integrations/nginx/?tab=host

まず、これを見てnginxのstatus_moduleを入れてください。
(ここまではdocker関係ないです)

要は、localhost:81でステータスが見れてたらOK。

公式ドキュメント

docker-composeを使ってnginxを監視する設定ぐらいサンプルがあるやろ!!!

コンテナ環境の場合は、オートディスカバリーのインテグレーションテンプレートのガイドを参照して、次のパラメーターを適用してください。

で、案内されるページに行っても、docker-composeのサンプルもなにもない・・・
https://docs.datadoghq.com/ja/agent/kubernetes/integrations/?tab=kubernetes

要は、適当にコンフィグファイル.yamlを作ってコピーするなり、マウントしてやればいいらしい?
サンプルファイル?なにそれ?

conf.d/.d/conf.yaml

で、nginx用の設定はこれらしい

<インテグレーション名>    nginx
<初期コンフィギュレーション>   空白または {}
<インスタンスコンフィギュレーション>   {"nginx_status_url": "http://%%host%%:81/nginx_status/"}

さらにわからん!!!!<インテグレーション名>って何を入れたらいいんですか?
どこに?何というファイル名で?
公式ドキュメントが不親切すぎる!!!!

datadogは有償ツール故に試してみた的な記事も殆どない・・・

ということで、以下が正解のdocker-compose.ymlファイルです。

docker-compose.yml

version: "3.8"
services:
  web:
    build:
      context: ./docker/nginx
    ports:
      - 80:80
    # 関係ない設定は削除
    # ここまでの設定はdatadogとは関係なし 81番ポートを開ける必要はなし
    # ここからがdatadogでログを取る核心部分の設定
    links:
      - dd-agent:dd-agent
    depends_on:
      - dd-agent
    labels:
      com.datadoghq.ad.check_names: '["nginx"]'
      com.datadoghq.ad.init_configs: '[{}]'
      com.datadoghq.ad.instances: '[{"nginx_status_url": "http://%%host%%:81/nginx_status"}]'
      com.datadoghq.ad.logs: '[{"source": "nginx", "service": "web"}]'


# datadogのコンテナ設定
  dd-agent:
    container_name: dd-agent
    image: datadog/agent:7
    environment:
      - DD_API_KEY=ここに自分のAPIキーを書く
      - DD_APM_ENABLED=true
      - DD_LOGS_ENABLED=true
      - DD_LOGS_CONFIG_CONTAINER_COLLECT_ALL=true
      - DD_AC_EXCLUDE="name:dd-agent"
    volumes:
     - /var/run/docker.sock:/var/run/docker.sock
     - /proc/:/host/proc/:ro
     - /sys/fs/cgroup:/host/sys/fs/cgroup:ro
    ports:
      - "8126:8126/tcp"

これでコンテナを立ち上げて、docker psで生存確認。healtyになっていたらOK。

$ docker ps
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS                    PORTS                                      NAMES
577f6b34b971        datadog/agent:7      "/init"                  39 seconds ago      Up 37 seconds (healthy)   8125/udp, 0.0.0.0:8126->8126/tcp           dd-agent

生きていれば、datadogのstatusチェック。

$ docker exec -it dd-agent agent status

このコマンドで、checkの中にnginxって文字列があってなにかしているようであればOK。(長いので省略)

    nginx (3.9.0)
    -------------
      Instance ID: nginx:[OK]
      Configuration Source: docker:docker://
      Total Runs: 4
      Metric Samples: Last Run: 7, Total: 28
      Events: Last Run: 0, Total: 0
      Service Checks: Last Run: 1, Total: 4
      Average Execution Time : 5ms
      Last Execution Date : 2020-10-27 10:20:20.000000 UTC
      Last Successful Execution Date : 2020-10-27 10:20:20.000000 UTC
      metadata:
        version.major: 1
        version.minor: 18
        version.patch: 0
        version.raw: 1.18.0
        version.scheme: semver

こんな基本的なアプリケーションの組み合わせのサンプルも記事も無いとかdatadog無いわ・・・・厳しいわ・・・

ハマリポイント

API_KEYじゃなくてDD_API_KEY
古いdd-agentを使っているとstatusコマンドが存在しなかった etc

多少参考になった記事

https://y-ohgi.com/2019-aws-handson/datadog/docker-compose/
https://tech.griphone.co.jp/2018/12/02/advent-calendar-20181202/
https://qiita.com/comefigo/items/4d867a39ad2fd5b9bbd2
https://qiita.com/spesnova/items/b1f2cc4e33ddf7cea285

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

【GCP】ローカルのDockerイメージをContainer RegistryにPushするまで

概要

ローカル環境で開発してビルドしたコンテナイメージを、ローカルから「Container Registry」のリポジトリにプッシュするための作業

参考

https://cloud.google.com/container-registry/docs/pushing-and-pulling#push_the_tagged_image_to

手順

1. gcloudの設定

  1. gcloudコマンドをローカル環境にインストール
  2. 初期設定
    • gcloud init

2. イメージのPush/Pull用サービスアカウント作成

自分のユーザーアカウントを使う場合、プロジェクトがいろいろと紐づいているとプロジェクトIDの選択ミスが怖いので、専用のサービスアカウントを作る。

  1. サービスアカウント作成
    • コンソールで作業
  2. 権限設定
  3. サービスアカウントのキーを作成し、ローカルで認証設定

3. Docker 認証設定

gcloud をDockerの認証ヘルパーとして使用するための設定

  1. ローカルで gcloud auth configure-docker を実行

4. Dockerイメージのプッシュ

※ もし複数アカウントがある場合は以下でアカウントを切り替える
gcloud config set account [ACCOUNT]

  1. ローカル イメージにレジストリ名でタグ付けする
    • 命名規則 : [HOSTNAME]/[PROJECT-ID]/[IMAGE]
      • [HOSTNAME] : 以下から選ぶ。これでイメージを保存する場所が決まる。
        • gcr.io は米国内のデータセンターでイメージをホストしていますが、今後は場所が変更される可能性があります。
        • us.gcr.io は米国内のデータセンターでイメージをホストしていますが、gcr.io によってホストされるイメージからは独立したストレージ バケットです。
        • eu.gcr.io は、欧州連合でイメージをホストします。
        • asia.gcr.io は、アジアのデータセンターでイメージをホストします。
      • [PROJECT-ID] : 対象のGoogle CloudプロジェクトのプロジェクトID
      • [IMAGE] : コンテナイメージの名前
    • タグ付けコマンド : docker tag [ローカル イメージ名またはイメージ ID] [レジストリ名]:[タグ(未指定はlatest)]
  2. プッシュ
    • docker push [レジストリ名]:[タグ(未指定はlatest)]

新規でプッシュすると、Container Registry上にリポジトリができる。

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

プロキシ環境下の Docker

Docker おじさんです。

今回は
「顧客の本番環境がプロキシを通さないとインターネットに出れないことが判明した!!!」
という状況で焦らないためのメモ。

Docker のインストール

Debian / Ubuntu 前提で。

プロキシ環境下なので以下は普通に通らないと思うが、~/.bashrc とかで環境変数 http_proxy などを設定しても sudo すると環境変数は引き継がれないのでそのままでは通らない。

$ sudo apt-get install docker.io

sudo-E オプションを付ければ環境変数を引き継げば通るが毎回 -E をつけるのが面倒なので、別の方法として apt の設定ファイルを書いてしまったほうが楽。

/etc/apt/apt.conf.d/00-proxy
Acquire::http::Proxy "http://{HOST}:{port}";
Acquire::https::Proxy "http://{HOST}:{port}";

RHEL / CentOS の人は yum 用の設定方法があると思うので適当にググってやっていって欲しい。

Docker Engine

docker pull などでイメージを落としてくる場合は Docker Engine にプロキシ設定をする必要がある。

単純に環境変数 HTTP_PROXY HTTPS_PROXY を設定すればいいのだが、最近は Systemd で動いていることがほとんどだと思うので Systemd の設定ファイルで環境変数を指定するのが手っ取り早い。

/lib/systemd/system/docker.service
[Service]
Environment=HTTP_PROXY=http://{HOST}:{port}
Environment=HTTPS_PROXY=http://{HOST}:{port}

Docker イメージのビルド時

Docker イメージのビルド時に限らないが、 apt-get install などでインターネットに出たい場合は、そのツールひとつひとつにプロキシ設定をする必要がある。

apt-get や pip などは環境変数を設定するだけでプロキシを通ってくれるので、とりあえず環境変数を設定しておき、個別に対応が必要なツールについては個別に対応していく、となる。ビルド時に環境変数を設定するには Dockerfile に環境変数を指定してもいいが、ARG を使うのがよさそう。

例えば Docker Compose の設定ファイルで args を指定する場合は、サービスの build オプションを以下のように指定する。

docker-compose.yml
  build:
    context: .
    args:
      - http_proxy=http://{HOST}:{port}
      - https_proxy=http://{HOST}:{port}
      - HTTP_PROXY=http://{HOST}:{port}
      - HTTPS_PROXY=http://{HOST}:{port}

ツールによって対応している環境変数名が大文字だったり小文字だったりするので、両方指定しておいたほうが良い。
(例えば apt-get は大文字の HTTP_PROXY を指定しても認識してくれない)

Docker コンテナ起動時

コンテナ起動時はビルド時と同様にツールひとつひとつにプロキシ設定をする必要があるため、個別対応以外で出来ることといえば環境変数を設定するだけとなる。

コンテナ起動時に毎回環境変数を指定するのは手間なので、 ~/.docker/config.json を書いておくとコンテナ内に HTTP_PROXY などを自動で設定してくれる機能を使うと楽。

~/.docker/config.json
{
  "proxies": {
    "default": {
      "httpProxy": "http://{HOST}:{port}",
      "httpsProxy": "http://{HOST}:{port}"
    }
  }
}

Configure Docker to use a proxy server | Docker Documentation

その他

Docker 以外の設定で環境変数では対応できないやつ (git とか curl とか boto3 とか) そのへんはググって個別によしなに設定する。

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

Dockerのpython:x.x.x-alpine imageでdjangoアプリを立ち上げmigrateしたときに"Cannot use ImageField because Pillow is not installed"エラーが出る問題

DjangoアプリをDockerに乗せて本番環境にデプロイするときに生じた問題です。
DjangoではImageファイルを扱う際にPillowというライブラリを使うのですが、このライブラリが厄介で、エラーを起こしやすいです。
次のDockerfileを使ってbuildします。

Dockerfile
###########
# BUILDER #
###########

# pull official base image
FROM python:3.7.3-alpine as builder

# set work directory
WORKDIR /usr/src/app

# set environment variables
#ENV PATH="/scripts:${PATH}"
ENV PYTHONUNBUFFERD 1
ENV PYTHONDONTWRITEBYTECODE 1

# install psycopg2 dependencies
RUN apk add --update --no-cache --virtual .tmp-build-deps postgresql-client jpeg-dev \
    .tmp-build-deps gcc build-base python3-dev musl-dev linux-headers \
    postgresql-dev
RUN apk add --update --no-cache --virtual .build-deps build-base python3-dev musl-dev \
    libc-dev linux-headers postgresql-dev musl-dev zlib zlib-dev gettext \
    postgresql-client gettext-dev libjpeg-turbo pcre
RUN apk add --update libxml2-dev libxslt-dev libffi-dev gcc libgcc openssl-dev curl
RUN apk add --update jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev libjpeg
RUN apk add --no-cache jpeg

# lint
RUN pip install --upgrade pip
RUN pip install --upgrade setuptools
RUN pip install flake8
RUN pip install pillow
COPY . .
RUN flake8 --ignore=E501,F401 .

# install dependencies
COPY ./requirements.txt .
RUN pip wheel --no-cache-dir --no-deps --wheel-dir /usr/src/app/wheels -r requirements.txt
RUN apk del .tmp-build-deps

#########
# FINAL #
#########

# pull official base image
FROM python:3.7.3-alpine

# create directory for the app user
RUN mkdir -p /home/app

# create the app user
RUN addgroup -S app && adduser -S app -G app
COPY --from=builder /usr/local/lib/python3.7/site-packages /usr/local/lib/python3.7/site-packages

# create the appropriate directories
ENV HOME=/home/app
ENV APP_HOME=/home/app/web
RUN mkdir $APP_HOME
#RUN mkdir $APP_HOME/staticfiles
#RUN mkdir $APP_HOME/mediafiles
WORKDIR $APP_HOME

# install dependencies
RUN apk update && apk add libpq
COPY --from=builder /usr/src/app/wheels /wheels
COPY --from=builder /usr/src/app/requirements.txt .
RUN pip install --no-cache /wheels/*
#RUN pip install pillow

# copy entrypoint-prod.sh
COPY ./entrypoint.prod.sh $APP_HOME

# copy project
COPY . $APP_HOME

# chown all the files to the app user
RUN chown -R app:app $APP_HOME

# change to the app user
USER app

#RUN chmod +x /home/app/web/entrypoint.prod.sh

# run entrypoint.prod.sh
ENTRYPOINT ["/home/app/web/entrypoint.prod.sh"]:

docker-compose.ymlは次のようにします。

docker-compose.yml
version: '3.7'

services:
  web:
    build:
      context: ./app
      dockerfile: Dockerfile
    command: gunicorn backend.wsgi:application --bind 0.0.0.0:8000
    ports:
      - 8000:8000
    env_file:
      - ./.env.dev
    depends_on:
      - db
  db:
    image: postgres:12.0-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - POSTGRES_USER=hello_django
      - POSTGRES_PASSWORD=hello_django
      - POSTGRES_DB=hello_django_dev
      - POSTGRES_HOST_AUTH_METHOD=trust
  nginx:
    build: ./nginx
    ports:
      - 1337:80
    depends_on:
      - web

volumes:
  postgres_data:


このように書いてdocker-compose up -d buildして、
docker-compose exec web python manage.py migrateすると、
記事タイトルのように"Cannot use ImageField because Pillow is not installed"エラーが起こります。
スクリーンショット 2020-10-27 14.49.19.png

エラー文に従ってdocker-compose exec web python -m pip install Pillowしてみます。
スクリーンショット 2020-10-27 14.52.00.png

というか、docker-compose exec web python -m pip listでライブラリを見ると、Pillowは無事インストールされています。
なぜだ......

調べるとこのエラーはよく起こるようで、pip install -m Pillowをしろだとか、alpineにapkで色々jpeg-devとかのdependenciesを入れろだとか、pythonとpillowのversionを変えろとか出てきます。色々試してみましたが、どうやら、alpineイメージではPillowを扱うことができないようです。

Dockerイメージをpython-x.x.x-alpineからpython-x.x-busterに変更して色々dependenciesを入れてbuildしたところ、無事migrateできました。解決法としてはシンプルです。django on docker(alpine)でPillowは使えません。以上です。

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

Dockerコンテナ内でcomposer updateしようとしたらproc_open(): fork failed と怒られた

環境

Docker for windowsを使用しています.
Docker Machineのバージョンは以下の通りです.

docker-machine.exe version 0.16.1, build cce350d7

Docker内でcomposer updateしようとした

LaravelをDockerコンテナ内で動かしているのですが,composer updateをしようとしたら怒れてしましました.

PHP Fatal error: Uncaught exception 'ErrorException' with message
'proc_open(): fork failed - Cannot allocate memory'

どうやらメモリ領域が足りないことが原因で起きたようです.
そこでスワップ領域を拡張しようと思い,以下のコマンドを実行したのですが,swapon failed: Operation not permittedと怒られました.

/bin/dd if=/dev/zero of=/var/swap.1 bs=1M count=1024
/sbin/mkswap /var/swap.1
/sbin/swapon /var/swap.1

権限を与えてもダメでした.

解決方法

Docker Machineのメモリを増やしたらうまくいきました.
Docker Machineを一度停止し,Oracle VM VirtualBox マネージャーを起動します.
2020-10-25.png

以下のように該当するMachineの設定を開き,システム>マザーボード>メインメモリでメモリを増やします.
自分の環境では2GBでうまくいきました.

2020-10-25 (1).png
※Machineを起動した状態では変更できません.落とすのを忘れないように.

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

ApolloサーバーとPrismaを使用したJWT認証

はじめに

本記事ではGraphQLを利用したユーザー認証についてテストを行った備忘録となります。
認証にはJWTとBcryptを利用しており、Prismaを使用するApolloサーバーにてテストをしました。

Prismaとは?

GraphQLサーバー(本記事ではGraphQLサーバーとしてApolloを利用)とデータベースを繋ぐORMの一つ。
噛み砕いて言うならば、スキーマ定義をしたQueryやMutationに応じたデータをデータベースから持ってきてくれるツールみたいなイメージです。

ORMとは下記の機能のまとまりのことを指します。

  1. データベースからデータを取得する
  2. 取得したデータをオブジェクト化する
  3. データの更新・変更などをデータベースに格納する

参考:もっとORMを使えるようになりたいので、見直してみた

JWTとは?

JWT(ジョット)とはJSON Web Token の略で、JSONデータに署名や暗号化を施す方法のことを指します。
本記事ではログイン認証に利用します。
詳しくはこちら

Prismaの設定

早速Prismaの設定からスタートしていきます?

$ mkdir jwt-Auth
$ cd jwt-Auth
$ npm init
$ npm install apollo-server graphql  prisma-client-lib
$ npm install -g prisma

プロジェクト作成後に、npm installが完了したら、
ORMとしてPrismaを使用するようにアプリケーションを設定します。

$ prisma init

そのままDockerを使い、Prismaの設定を行なっていきます。

? Set up a new Prisma server or deploy to an existing server? 
❯ Create new database                 Set up a local database using Docker 
? What kind of database do you want to deploy to? 
❯ PostgreSQL        PostgreSQL database 
? Select the programming language for the generated Prisma client 
❯ Prisma JavaScript Client

成功すると下記のような案内が表示されます。

Created 3 new files:                                                                          

  prisma.yml           Prisma service definition
  datamodel.graphql    GraphQL SDL-based datamodel (foundation for database)
  docker-compose.yml   Docker configuration file

Next steps:

  1. Start your Prisma server: docker-compose up -d
  2. Deploy your Prisma service: prisma deploy
  3. Read more about Prisma server:

Dockerコンテナの起動

Dockerコンテナを起動する前に、生成されたファイルの設定変更をします。

①docker-compose.yml内の中ほどある、portに関する設定のコメントアウトを外す。
こちらがコメントアウトされたままだと、localhostで立ち上げることが出来ません。

docker-compose.yml
# Uncomment the next two lines to connect to your your database from outside the Docker environment, e.g. using a database GUI like Postico
    ports:
      - "5432:5432"

②datamodel.graphqlの書き換えをします。こちらのファイルがORMとして機能するために必要なファイルの元になります。

datamodel.graphql
type User {
  id: ID! @id
  name: String!
  email: String! @unique
  password: String!
}

③prisma.ymlは変更不要ですが、下記のようになります。

prisma.yml
endpoint: http://localhost:4466
datamodel: datamodel.prisma

generate:
  - generator: javascript-client
    output: ./generated/prisma-client/

準備ができたら、先ほどの「Next steps」の案内に従い、コンテナを起動させます。

$ docker-compose up -d 
$ prisma deploy
$ prisma generate

以上のコマンドを正常に実行すると、datamodel.prismaファイルから生成されたORMとして機能するために必要なファイルが作成されます。

下記のようにPrismaインスタンスをアプリケーションにインポートするだけで利用すると、ミューテーションやクエリを実行するときに、データベースを実際に操作できるようになります。

const { prisma } = require('./generated/prisma-client')

Apolloサーバーに関するコードを書く

Prismaの設定が完了したら、GraphQlサーバーとして、Apolloを利用する準備をしていきます。bcryptとはパスワードのハッシュ化のために利用するライブラリです。

$ mkdir resolver 
$ touch index.js schema.js  resolver/Mutation.js 
$ npm install bcrypt jsonwebtoken

先ずはスキーマを書きます。
今回はサインアップとサインインを試すべく、それに当たるスキーマをMutation内で定義しています。

schema.js
const {gql} = require('apollo-server');

const typeDefs = gql`
type Query {
  users(query: String): [User!]!
}

type Mutation {
  createUser(data: CreateUserInput!): AuthPayload!
  login(data: LoginUserInput!): AuthPayload!
}

type AuthPayload {
  token: String!
  user: User!
}

input CreateUserInput {
  name: String!
  email: String!
  password: String!
}

input LoginUserInput {
  email: String!
  password: String!
}

type User {
  id: ID!
  name: String!
  email: String
  password: String!
}
`
module.exports = typeDefs;

JWTとbcryptはこちらで利用しています。
Prismaはすべてのリゾルバー間で共有するので、第三引数のcontextとして使います。

Mutation.js
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');

const Mutation = {
    async createUser(parent, args, { prisma }, info) {
        const { data: { email, name, password } } = args;
        const newUser = await prisma.createUser({
          email,
          name,
          // bcryptでパスワードをハッシュ化
          password: bcrypt.hashSync(password, 3)
        });
          // サーバーがJWTトークンを発行
        return {token : jwt.sign(newUser, "supersecret")};
    },
    async login(parent, args, { prisma }, info) {
        const { data: { email, password } } = args;
         // メールアドレスと照合
        const [ signInUser ] = await prisma.users({
          where: {
            email
          }
        })
        if (!signInUser) throw new Error('Unable to Login');
         // パスワードと照合
        const isMatch = bcrypt.compareSync(password, signInUser.password);
        if (!isMatch) throw new Error('Unable to Login');
         // 認証済みのトークンが返ってくる
        return {token : jwt.sign(signInUser, "supersecret")};
    },
}

module.exports = Mutation

最後にApolloサーバーを立ち上げする設定の処理を書きます。

index.js
const { ApolloServer } = require('apollo-server');
const Mutation = require('./resolver/Mutation')
const typeDefs = require('./schema')
// datamodel.prismaファイルから生成されたPrismaインスタンス
const { prisma } = require('./generated/prisma-client')


const server = new ApolloServer({
    typeDefs: typeDefs,
    resolvers: {
        Mutation
    },
    context: {
        prisma
    }
})

server.listen().then(({ url}) => {
    console.log(`? Server ready at ${url}`);
});

GraphQL IDEにてテストをする

GraphQL IDEを使ってテストをします。

$ node index.js
? Server ready at http://localhost:4000/

http://localhost:4000/

サインアップ

IDE上でname,email.passwordを含むクエリを書きます。

スクリーンショット 2020-10-27 1.44.28.png

JWTトークンが返ってきました。

サインイン

続いてサインインの確認です。
サインアップと同じ、email,passwordをクエリで書きます。

スクリーンショット 2020-10-27 1.46.10.png

サインアップの時と同一のJWTトークンが返ってきました!
成功です!

おわりに

以上、GraphQLにおけるログイン認証をテストしてみました。
PrismaとDockerで素早く環境を作ることができ、その後はほとんど意識することなく、コードを書けたのはGraphQLの強みであるように感じました。

それでは、また?

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