20200426のdockerに関する記事は24件です。

OpenProject に Metabase をドッキングしたら最強のダッシュボードが作れるかも

なぜ書いた?

  • 趣味で調べたことを職場で参照したい
  • もしかすると参考になる人がいるかもしれない
  • OpenProject と Metabase の可能性に震えたから

OpenProject の準備

OpenProjectは、場所に依存しないチームコラボレーションのためのWebベースのプロジェクト管理システムです。

まず OpenProject のインストール方法は下記の3つであると公式にあります。
docker(-compose) を使うのが手軽そうなのでこれでやってみます。

  • DEB/RPM packages
    • 既存のマシンなどへ直接インストール(推奨)
  • docker
    • docker-compose で起動
  • Installation with Univention Corporate Server
    • VMイメージを入手

Installing OpenProject | OpenProject Help & Documentation
https://docs.openproject.org/installation-and-operations/installation/

docker を使ったインストール方法は下記の2つであると公式にあります。
推奨されている前者の方法でやってみます。

  • One container per process
    • WebやDBなどの機能ごとにコンテナを分けます(推奨)
  • All-in-one container
    • 1つのコンテナで全ての機能を賄います

Install OpenProject with Docker | OpenProject Help & Documentation
https://docs.openproject.org/installation-and-operations/installation/docker/

とりあえずローカルで試運転する分には上記のページに従って下記のコマンドを打つだけで起動します(簡単!)。ですが Metabase と組み合わせたいので起動の前に docker-compose.yml を編集します。

# docker-compose.yml などを取得する
git clone --depth=1 --branch=stable/10 https://github.com/opf/openproject
# docker-compose.yml のあるディレクトリへ移動する
cd openproject
# デタッチモードで起動
docker-compose up -d

docker-compose.yml を読み解くと主な要素は下記のように配置されると分かります。
ここへ Metabase を追加してみます。

deployment1.png

Metabase の準備

メタベースは、社内の誰もが質問したり、データから学んだりするための簡単でオープンソースな方法です。

Metabase を加えて下記の構成となるよう docker-compose.yml を編集します。

deployment2.png

そして出来上がった docker-compose.yml がこちら。
docker-compose up -d で起動させると http://localhost:8080/ に OpenProject が、 http://localhost:3000/ に Metabase が起動します。Metabase の起動が完了するまではしばらく待つかもしれません。

version: "3.7"

networks:
  frontend:
  backend:
  metabase-backend:

volumes:
  pgdata:
  opdata:
  metabase-pgdata:

x-op-restart-policy: &restart_policy
  restart: unless-stopped
x-op-image: &image
  image: openproject/community:${TAG:-10}
x-op-app: &app
  <<: *image
  <<: *restart_policy
  environment:
    - "RAILS_CACHE_STORE=memcache"
    - "OPENPROJECT_CACHE__MEMCACHE__SERVER=cache:11211"
    - "OPENPROJECT_RAILS__RELATIVE__URL__ROOT=${OPENPROJECT_RAILS__RELATIVE__URL__ROOT:-}"
    - "DATABASE_URL=postgres://postgres:p4ssw0rd@db/openproject"
    - "USE_PUMA=true"
    # set to true to enable the email receiving feature. See ./docker/cron for more options
    - "IMAP_ENABLED=false"
  volumes:
    - "opdata:/var/openproject/assets"
  depends_on:
    - db
    - cache
x-mb-app: &mb-app
  image: metabase/metabase
  <<: *restart_policy
  environment:
    - "MB_DB_TYPE=postgres"
    - "MB_DB_DBNAME=metabase"
    - "MB_DB_PORT=5432"
    - "MB_DB_USER=postgres"
    - "MB_DB_PASS=p4ssw0rd"
    - "MB_DB_HOST=metabase-db"
  depends_on:
    - db
    - metabase-db

services:
  db:
    image: postgres:10
    <<: *restart_policy
    stop_grace_period: "3s"
    volumes:
      - "pgdata:/var/lib/postgresql/data"
    environment:
      - POSTGRES_PASSWORD=p4ssw0rd
      - POSTGRES_DB=openproject
    networks:
      - backend

  cache:
    image: memcached
    <<: *restart_policy
    networks:
      - backend

  proxy:
    <<: *image
    <<: *restart_policy
    command: "./docker/proxy"
    ports:
      - "8080:80"
    environment:
      - APP_HOST=web
      - "OPENPROJECT_RAILS__RELATIVE__URL__ROOT=${OPENPROJECT_RAILS__RELATIVE__URL__ROOT:-}"
    depends_on:
      - web
    networks:
      - frontend

  web:
    <<: *app
    command: "./docker/web"
    networks:
      - frontend
      - backend

  worker:
    <<: *app
    command: "./docker/worker"
    networks:
      - backend

  cron:
    <<: *app
    command: "./docker/cron"
    networks:
      - backend

  seeder:
    <<: *app
    command: "./docker/seeder"
    restart: on-failure
    networks:
      - backend

  metabase-app:
    <<: *mb-app
    ports:
      - "3000:3000"
    networks:
      - backend
      - metabase-backend

  metabase-db:
    image: postgres:10
    <<: *restart_policy
    stop_grace_period: "3s"
    volumes:
      - "metabase-pgdata:/var/lib/postgresql/data"
    environment:
      - POSTGRES_PASSWORD=p4ssw0rd
      - POSTGRES_DB=metabase
    networks:
      - metabase-backend

Metabase が起動したら初期設定時に OpenProject の DB を登録してしまいましょう。
「名前」は任意、「データベースユーザー名」と「ポート」は postgres のデフォルトですが、「ホスト」から「データベースパスワード」のその他の項目は docker-compose.yml の db サービスの設定から読み取れる内容で埋めます。

Screenshot_2020-04-26 Metabase.png

OpenProject の DB スキーマを紐解く

※ まだあまり紐解けていないので随時更新予定

OpenOroject の Work packages(Redmine におけるチケットに相当する概念) を格納しているテーブルは、Metabase からは Work Packages という名前で見えるようになります(生のSQLで参照する場合は work_packages)。このテーブルには多数の列がありますが下記の列に注目してみます。

  • Story Points
    • 相対見積もり
  • Derived Estimated Hours
    • 配下のタスクの見積もりの合計(時間単位)

まず一例としてプロダクトバックログ項目に対して割り当てた相対見積もりと、いざ項目を実行しようとしてタスクへブレークダウンした後の時間見積もりが相関しているかウォッチできる散布図を作ってみました(データが少ないので見栄えしない)。

Screenshot_2020-04-26 Test · ダッシュボード · Metabase.png

最終的には99%の確率で納期を守るにはの考え方を使ってプロジェクトの成功率を表示したいと思っています。OpenOroject のタイムトラッキング機能を有効にするとタスクの実行にかかった時間を入力できるようになりますが Work Packages テーブルに直接は反映されないので器用に抽出する必要がありそうです。

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

Dockerの存在意義とは何か調べてみた(個人的見解も含みます)

この記事の目的

技術的にDockerが使えるようになりたくて先日環境構築をして、「この作業いるのだろうか...というか逆にコンテナ消したり作ったりするから通信量ばかになってなくないか...なんか重いし...」とふと疑問が湧いてきたので調べてみました。

Dockerとは結局何者なのか

非常に軽い仮想環境(バーチャルマシン)です。似たようなものとしてVMware,VirtialBox,bootcampなどがあります。

用途は環境構築(OS)からプロジェクト完成までの変化を記録してくれる、Gitの亜種だと理解するといいそうです。(筆者の感覚だとGitHubの亜種です)

環境構築を多人数で行う時、途中までをpushしておいて、途中から別な人がpullして付け加えていく使い方になります。

docker pullgit pullと同じで差分だけダウンロードされます。

Dockerの良さは?

バージョン管理の容易さと環境の準備の容易さ

ローカルの開発環境から独立し、OSの階層からアップロードされたものだけを使うため、gemのバージョンやOSの統一などを一切気にしなくて良くなります。MojaveとCatarinaという違いどころか、Windowsで同じプロジェクトをやっても大丈夫です。

コンテナ化のシステムではダントツ軽い

通常コンテナを使う際にはOSを入れなければいけないのですがdockerだとOSにubuntuを使用すればストレージの使用量が123MBで済むためVMwareやbootcampなどと比べた時圧倒的に仮想環境で使用するストレージ容量が小さいです。bootcampでwindowsを快適に使うには50GBは必要です。

デプロイがわかりやすい

AWSのEC2(Elastic Cloud Container)を使わずdockerで作成し、仮想環境で作ったものをそのままpullすればwebに公開できるのでわかりやすい、らしいです。(未実施なので今後確認します。ただ確かにEC2で作業していた時はコンパイルの問題とアプリケーションの起動の問題で悩まされており、それがDockerfileにRun ~ と書いてあるだけで動くならとても楽だと思います。ちなみに前回はcapistranoという自動デプロイ機能のgemのおかげでなんとか乗り切りました。)

参考

https://iga-ninja.hatenablog.com/entry/2018/06/28/091412

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

【Docker】基本をざっくりメモ

Dockerとは、、

サーバ環境をパッケージングできる仕組み。
osのバージョンから使用するライブラリ・ミドルウェアの構成等の実行環境をパッケージングすることで固定する。
そうしてDockerで作成された開発環境は配布しやすく、そのパッケージがあれば、環境を作ったり捨てたり(消したり)が簡単にできる。

アプリケーション起動・実行までの流れ

1.アプリケーションの環境を Dockerfile ファイルで定義する。このファイルは、どこでも再利用可能。

2.アプリケーションを構成する各サービスを docker-compose.yml ファイルで定義する。そうすることで、独立した環境を一斉に実行できるようにしている。

3.最後に、docker-compose up を実行すると、Composeがアプリケーション全体を起動・実行する。

Dockerfileで行うこと

(例)
FROM ruby:2.5.1-stretch

ENV ENTRYKIT_VERSION 0.4.0

WORKDIR /path

RUN apt-get update 
〜(後略)                                                                                                
  • FROMで元にするOS(ベースイメージ)の指定
  • ENVで環境変数の指定( の形式)
  • WORKDIRでRUN等の命令実行時の作業場所の明示
  • RUN apt-getで必要になるライブラリのインストール

  などなど、、

docker-compose.ymlで行うこと

(例)
version: "3"
volumes:
  mysql_8_0-data:
  redis-data:
  vendor_bundle_2_5_1:
  vendor_assets_2_7:
  node_modules:

services:
  mysql:
    image: mysql:8.0
    environment:
    networks:
      - default
    ports:
      - '33306:3306'
  redis:
    image: redis:alpine
    networks:
      - default
  app_name:
    build:
      context: .
      dockerfile: Dockerfile.dev
    depends_on:
      - mysql
      - redis
    networks:
      - default
    command: /bin/sh -c "rm -f tmp/pids/server.pid && bundle exec rails server -b 0.0.0.0
  • versionでdocker-composeの使用バージョンの指定
  • servicesでアプリケーションを動かす為の各要素(railsとmysqlとredisと…)を定義。更にそれぞれの設定をその下に記述。

 
 などなど、、

docker-compose.ymlの考え方

上述したservicesに記載のある各要素もそれぞれコンテナであり、docker-compose upを行うことで、docker-compose.ymlの内容を元に別々に分かれているコンテナが一つの環境としてまとめられる。

実際のサーバ構築で例えるとすると、rails、mysql、redisがそれぞれ動くサーバを立てる、更にそれぞれがネットワークで繋げるという状況を記述しているイメージ。

参考

終わりに。

転職の為、未経験の状態からRailsを学習しております。正しい知識を着実に身に着け、実力のあるエンジニアになりたいと考えています。継続して投稿していく中で、その為のインプットも必然的に増え、成長に繋がるかと考えています。
今現在、初心者だからといって言い訳はできないですが、投稿の内容に間違っているところや、付け加えるべきところが多々あるかと思いますので、ご指摘頂けると幸いです。この記事を読んで下さりありがとうございます。

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

Docker volume の公式ドキュメントが分かりやすかった話

はじめに

最近、くろかわこうへいさんや、KENTAさんの動画をよく見る中で「あれ、Docker できないのやばくね?」と、ふと思いDocker の学習を始めました。参考書やネットでちょっと調べていくと「あれ、思ってたよりも難しくないじゃん」と思っていた矢先に、volume が出てきて一気につまづきまいした。記事などもいろいろ読んで調べてみたものの、よくわからず挫折しかけていた時に、公式ドキュメントに出会い読んでみると「何これわかりやすいじゃん!」ってなりました(笑)。

ということで、公式ドキュメントを読んで自分なりに理解したことをまとめます。

実行環境

  • Windows Home 10
  • Docker Toolbox v19.03.1

この記事を読むとわかること

  • volume とは
  • Dockerをデータの永続化の具体的な方法
  • データのマウントの具体的な挙動及び実装方法
    • bind mount
    • volume
    • tmpfs mount

Volume には 2 つの意味がある

後述するが、データを永続化させる方法は bind mountvolume の2 種類ある。ただ、どちらも -v--volume を使う。つまり、volume という単語には 2 つの意味があることになる。

  • データをマウントするための機能(-v, --volume)
  • Dockerのリソース内にあるコンテナの実行データを保管する場所

この記事では前者の機能を示す volume を データのマウントと定義する。

なぜデータのマウントが必要か

そもそもなぜ、データのマウントが必要なのか?

それは、コンテナ内部にデータを保存しても、コンテナ破棄すると消えてしまうため、データを永続化する際は、コンテナの外にデータを置く必要があるため。

データをマウント方法は 3 つ

概要

データのマウント方法は 3 つある。データを永続化させる場合は Bind mountVolume を使う。

  • Bind mount
  • Volume
  • Tmpfs mount
種類 データの保管場所 永続化
Bind mount ホストディレクトリ
Volume Docker のリソース
Tmpfs mount メモリ ×

data-mount
出典:docker docs

Bind mount

  • 特徴

    • ホストディレクトリやファイルがコンテナにマウントされる
    • コンテナ内のデータの変更に応じてホスト側のファイルも変更される
  • 用途

    • データを永続化させたい
    • 開発環境でホスト側のソースコードの修正を反映させたい

      ※ 本番環境のイメージではマウントでデータをコンテナに反映させるのではなく、copyを使うことが推奨されている。

  • 実装方法

    • -v または --volume を使う

      オプションの設定が 1 つのフィールドに固まっており、コンテナにデータのマウント先のディレクトリがなければ自動的に作成される。

    • --mount を使う

      オプションの設定が複数のフィールドに分かれているコンテナにマウント先のディレクトリが無ければ、エラーを返す。(※筆者の環境ではディレクトリが自動作成された)


  • volume_testディレクトリをマウントしてみる。ディレクトリの中は text.txt のみ。

volume_test
    test.txt

テキストファイルの内容。

test.txt
test

volume_testディレクトリに移動する。

まずは、-v--volume)コマンドでカレントディレクトリを ubuntu コンテナ内のすでに存在する /usr/src/var/tmp にマウントしてみる。

> docker run -it --name bindmount -v $(pwd):/usr/src/var/tmp ubuntu bash
root@eab26b27a693:/# cd usr/src/var/tmp
root@eab26b27a693:/usr/src/var/tmp# ls
test.txt

きちんと ディレクトリのデータがマウントされていることが分かる。ファイルの内容もtest から mount success! に変更してみる。

root@eab26b27a693:/usr/src/var/tmp# cat test.txt
test
root@eab26b27a693:/usr/src/var/tmp# echo mount success! > test.txt
root@eab26b27a693:/usr/src/var/tmp# cat test.txt
mount success!

実際にホスト側のファイルを確認してみると変更が反映されている!

次に、 ubuntu コンテナ内に存在しない /volume_test にマウントしてみる。

> docker run -it --name bindmount -v $(pwd):/volume_test ubuntu bash
root@b3e9bf711b7e:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  volume_test
root@b3e9bf711b7e:/# cd volume_test
root@b3e9bf711b7e:/volume_test# ls
test.txt

存在しないディレクトリにマウントした際には新しくディレクトリが作られている。先程と同様にファイルの内容もtest から mount success! に変更してみる。

root@b3e9bf711b7e:/volume_test# cat test.txt
test
root@b3e9bf711b7e:/volume_test# echo mount success! > test.txt
root@b3e9bf711b7e:/volume_test# cat test.txt
mount success!

こちらでもホスト側のファイルを確認してみると変更が反映されている!

次に --mount コマンドでカレントディレクトリを ubuntu 内のすでに存在する /usr/src/var/tmp にマウントしてみる。-v とは違いマウントの仕方やホスト側のディレクトリ、マウントのディレクトリといった複数のオプションをカンマつなぎで記述する。

> docker run -it --name bindmount --mount type=bind,source="$(pwd)",target=/usr/src/var/tmp ubuntu bash
root@f77d388c204e:/# cd usr/src/var/tmp
root@f77d388c204e:/usr/src/var/tmp# ls
test.txt

--mount を使った場合でも同様にマウントできた。実際にコンテナ内のファイルを編集した際は上記の内容と同様に、ホスト側のファイルも編集された。

次に、ubuntu コンテナに存在しないディレクトリ( volume_test )にマウントしてみる。

docker run -it --rm --name bindmount --mount type=bind,source="$(pwd)",target=/volume_test ubuntu bash
root@a738ae0ebbd0:/# ls
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var  volume_test

volume_test が存在している!!! マウントできた!?

公式ドキュメントによると、

If you use --mount to bind-mount a file or directory that does not yet exist on the Docker host, Docker does not automatically create it for you, but generates an error.
出典:docker docs

つまり、--mount を使ってコンテナにバインドマウントする際は、コンテナ内にすでに存在するディレクトリにマウントしないとエラーが出る。なぜできたのだろう??

バインドマウントできているか確かめてみる。

root@a738ae0ebbd0:/# cd volume_test/
root@a738ae0ebbd0:/volume_test# cat test.txt
test
root@a738ae0ebbd0:/volume_test# echo mount sucess! > test.txt
root@a738ae0ebbd0:/volume_test# cat test.txt
mount sucess!

ホスト側のファイルも変更されているので、バインドマウントができている。なぜだろう??

ちなみに-v, --mmount どちらを使ってもマルチコンテナ間でもデータの共有は可能。

Volume

  • 特徴

    • docker リソース内のデータがコンテナにマウントされる
    • ホストディレクトリに依存しない
  • 用途

    • データを永続化させたい
    • 開発環境でソースコードの修正を反映させる以外の目的
  • 実装方法
    bind mount と同じ。-v または --mount を使う。


  • まずは volume_test という名前のボリュームを作る。

$ docker volume create volume_test
volume_test
$ docker volume ls
local               volume_test

まずは、-v--volume)コマンドでカレントディレクトリを ubuntu コンテナ内のすでに存在する /usr/src/var/tmp にマウントしてみる。また、ボリュームが存在しない場合は自動でボリュームが作成される。test.txt に mount success! と入力してコンテナを閉じる。

$ docker run -it --name volume_mount -v volume_test:/usr/src/var/tmp ubuntu bash                                        root@fe23da2e739c:/# cd /usr/src/var/tmp
root@fe23da2e739c:/usr/src/var/tmp# ls
root@fe23da2e739c:/usr/src/var/tmp# touch test.txt
root@fe23da2e739c:/usr/src/var/tmp# echo mount success! > test.txt
root@fe23da2e739c:/usr/src/var/tmp# cat test.txt
mount success!
root@fe23da2e739c:/usr/src/var/tmp# exit

コンテナを再度立ち上げて、test.txtが存在するか確認してみる。

$ docker container rm volume_mount
volume_mount
$ docker run -it --name volume_mount -v volume_test:/usr/src/var/tmp ubuntu bash
root@e54d18741135:/# cat usr/src/var/tmp/test.txt
mount success!

マウントできている!ubuntu コンテナに存在しないディレクトリにマウントしても同様の結果が得られる。

次に、次に --mount コマンドでカレントディレクトリを ubuntu 内のすでに存在する /usr/src/var/tmp にマウントしてみる。先程と同様に、test.txt に mount success! と入力してコンテナを閉じる。

$ docker run -it --name volume_mount --mount source="volume_test",target=/usr/src/var/tmp ubuntu bash                   
root@03074d3166a9:/# echo > usr/src/var/tmp/test.txt
root@03074d3166a9:/# cat usr/src/var/tmp/test.txt

root@03074d3166a9:/# echo mount success! > usr/src/var/tmp/test.txt
root@03074d3166a9:/# cat usr/src/var/tmp/test.txt
mount success!
root@03074d3166a9:/# exit

再度、volume_test をマウントしてコンテナを立ち上げる。

$ docker run -it --name volume_mount --mount source="volume_test",target=/usr/src/var/tmp ubuntu bash
root@9fe26cd9575f:/# cat usr/src/var/tmp/test.txt
mount success!

マウントできている!ubuntu コンテナに存在しないディレクトリにマウントしても同様の結果が得られる。

ちなみに-v, --mmount どちらを使ってもマルチコンテナ間でもデータの共有は可能。

Tmpfs mount

  • 特徴

    • マルチコンテナ間でデータの共有はできない
    • コンテナが止まるとホストメモリ上に保存されたファイルは消える
    • Docker on Linux でのみ動作する
  • 用途

    • 一時的にデータを退避させたい
    • セキュリティ的な理由で、ホストディレクトリやDocker リソース内の書き込み可能な領域にファイルを保管したくない
  • 実装方法

    • -tmpfs を使う

      マウントディレクトリ以外のオプションの設定が不可、コンテナにデータのマウント先のディレクトリがなければ自動的に作成される。

    • --mount を使う

      オプションの設定が複数のフィールドに分かれているコンテナにマウント先のディレクトリが無ければ、エラーを返す。

まとめ

  • データの永続化の種類は二つ
    • bind mount
    • volume

それぞれの違いは、永続化データの保存領域。使い分けは、開発においてソースコードの修正をコンテナにも反映させたいといったホストOSのファイルに依存することなら bind mount そうでなければ、volume を使う。

  • 一時的にデータを退避させるなら tmpfs mount を使う。

初心者なので、至らぬところはあるかと思いますがご指摘いただいたけると幸いです :bow_tone1:

参考

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

AWS X-RayをJavaで色々動かして試してみる

前提条件

X-Ray初心者向け。なんとなくは知ってるけど、具体的に何がどこまでできて、どうやって実装するかを色々試してみながら確認した記事。

環境としては、Spring Boot+MavenでWebアプリを実装している。依存関係の解決方法以外はGradleも同じはず。

X-RayのDockerコンテナイメージを作る。

まずは、適当なEC2とかでコンテナイメージを作る。
今回は、AWSのサンプルをベースに作ってみよう。

$ git clone https://github.com/aws-samples/aws-xray-fargate

buildspec.yml に書いてあるコマンドを、実行していってみる。

$ aws ecr get-login --no-include-email --region ap-northeast-1

でログイン情報を取得後、実行。ap-northeast-1は利用しているリージョンを指定する。

$ docker build -t xray:latest .

作ったコンテナイメージは正常性確認をしてみよう。以下を参考にする。
それぞれのdocker runのオプションの意味も記載されているので読んでみると良い。

【公式】ローカルで X-Ray デーモンを実行する

$ docker run \
  --attach STDOUT \
  -v ~/.aws/:/root/.aws/:ro \
  --net=host \
  -e AWS_REGION=ap-northeast-1 \
  --name xray \
  -p 2000:2000/udp \
  xray -o

あと、EC2のロールにAWSXRayDaemonWriteAccessのIAMポリシをつけておく。

アプリケーションのX-Ray対応

受信リクエスト対応

以下の開発者ガイドを参考にしながら、アプリケーション側でX-Rayのログをデーモンに送るようにする。

【公式】AWS X-Ray SDK for Java

受信リクエストの対応をするだけなら簡単なようだ。WebConfig.javaなクラスを以下の様に実装する。ApigwTestは、サンプルで作ったWebアプリの名前。

WebConfig.java
package com.example;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
import javax.servlet.Filter;
import com.amazonaws.xray.javax.servlet.AWSXRayServletFilter;

@Configuration
public class WebConfig {

  @Bean
  public Filter TracingFilter() {
    return new AWSXRayServletFilter("ApigwTest");
  }
}

X-RayはAWSのSDKを使う必要があるため、pom.xmlに以下を記述して依存関係を解決する。

pom.xml
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.amazonaws</groupId>
                <artifactId>aws-xray-recorder-sdk-bom</artifactId>
                <version>2.4.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-xray-recorder-sdk-core</artifactId>
        </dependency>
    </dependencies>

さて、このアプリを起動してアクセスすると、↓こんな感じでトレースができるようになる。

キャプチャ6.PNG

詳細情報の取得

さらに、受信リクエストを受けたノードの情報を取得できるように、↑で作ったWebConfigクラスに以下のコードを入れてみる。

import com.amazonaws.xray.AWSXRay;
import com.amazonaws.xray.AWSXRayRecorderBuilder;
import com.amazonaws.xray.plugins.EC2Plugin;
import com.amazonaws.xray.plugins.ECSPlugin;

  static {
      AWSXRayRecorderBuilder builder = AWSXRayRecorderBuilder.standard().withPlugin(new EC2Plugin()).withPlugin(new ECSPlugin());

      AWSXRay.setGlobalRecorder(builder.build());
  }

これをEC2上で実行した場合は、以下のように、サービスマップにEC2インスタンスであることが表示されるようになる。

キャプチャ7.PNG

ダウンストリームのトレース対応

さらに、HTTPクライアントとして、ダウンストリームのWebサービスの情報も取得する場合は、コントローラの中に↓こんなのを入れてみる。

import com.amazonaws.xray.proxies.apache.http.HttpClientBuilder;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.impl.client.CloseableHttpClient;
import java.io.IOException;
(中略)
    public int HttpClient(String URL) throws IOException {
        int statusCode = 500;

        CloseableHttpClient httpclient = HttpClientBuilder.create().build();
        HttpGet httpGet = new HttpGet(URL);
        CloseableHttpResponse clientResponse = httpclient.execute(httpGet);

        try {
            statusCode = clientResponse.getStatusLine().getStatusCode();
        } finally {
            clientResponse.close();
        }

        return statusCode;
    }

また、com.amazonaws.xray.proxies.apache.http.HttpClientBuilderをインポートするために、pom.xmlにも以下の依存関係を追記する。

pom.xml
    <dependencies>
        <dependency>
            <groupId>com.amazonaws</groupId>
            <artifactId>aws-xray-recorder-sdk-apache-http</artifactId>
        </dependency>
    </dependencies>

すると、以下のようにダウンストリームの情報も取得できるようになる。

キャプチャ8.PNG

ちなみに、このダウンストリームのサービスはLambda関数で実装していたので、ふと気になってLambda関数側でX-Rayの設定を有効化すると、↓こんな感じで、重複した要素は取得しなくなった。賢い。

キャプチャ9.PNG

ECS on Fargateで動かす

まずは、ここまでで動作確認したX-RayのコンテナをECRにPUSHする。
事前にxrayのリポジトリを作っておくのを忘れないように。

$ docker tag xray:latest [AWSのアカウントID].dkr.ecr.[リージョン].amazonaws.com/xray:latest
$ docker push [AWSのアカウントID].dkr.ecr.[リージョン].amazonaws.com/xray:latest

また、ここでもECSのタスクロールとタスク実行ロールにAWSXRayDaemonWriteAccessを付与しておく。

コンテナのタスク定義に、↑でPUSHしたxrayのイメージを入れる。
CloudFormationテンプレートで言えば、ContainerDefinitions内で、既存のコンテナ定義に並べて以下の定義を書く。awsvpcを使わないECS on EC2の場合は他にも設定が必要だが、Fargateの場合は、awsvpcで動くので、簡単に加えられるようだ。

    - Name: X-Ray-Daemon
      Image: !Sub ${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/xray:latest
      Cpu: 32
      MemoryReservation: 256
      PortMappings:
        - ContainerPort: 2000
          Protocol: udp

Lambda側のアクティブトレースを有効化すると、EC2と同様に取得することができた。

キャプチャ10.PNG

ただし、Lambda側のアクティブトレースを無効にすると、リクエストに対するトレースは取得できたが、ダウンストリームのトレースが取得できなかった。何かまだ足りていない設定があるのかもしれない。

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

初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)公開編パート1(NodePort)

背景

個人的にインフラの知識以上にこれからのアプリケーションが動く環境を作ってデプロイしたりしてこれからの知識を身に着けたい。そしてより一層、自分の知識のアップデートをしたいと思いました。

その中でこの本に出会い、これから少しずつやったことを残し、未来の自分への手紙としてもあり、見つめ直せればと思いました。

引用や参考と今回の自分の勉強用の書籍の紹介

技術評論社『Kubernetes実践入門』のサンプルコード
Kubernetes実践入門 プロダクションレディなコンテナ&アプリケーションの作り方

実際の学びについて

書籍を読みながら、章ごとに少しずつ進めていきたいと思います。
GitHub のソースコードも使いながら学んで行きたいと思います。
この章の勉強は本当に書籍の写経が主になるかもしれません・・・

勉強開始

  • アプリケーションを外部に公開する方法を学びます
    • NodePort を使って公開する
    • 外部 LoadBalancer を使って公開する
    • Ingress を使って公開する

今回は「NodePort を使って公開する」をやっていこうと思います

NodePort を使って公開する

  • すべてのノードに同じポートが開放される
  • ポートは 3000-32767 までが指定できる
  • expose コマンドでも実施できる

範囲外だと下記のようにエラーが出るし、Service でもできることを一旦確認

$ kubectl create service nodeport invalid-nodeport --tcp 8086 --node-port 32768
The Service "invalid-nodeport" is invalid: spec.ports[0].nodePort: Invalid value: 32768: provided port is not in the valid range. The range of valid ports is 30000-32767

マニュフェスト作成

Serviceのマニュフェストを作る
$ kubectl expose --type NodePort --port 8065 deployment mattermost --dry-run -o yaml > mattermost-service.yaml
gitと自分で作成したマニュフェストの差分
--- a/ch3.6.1/manifests/mattermost/mattermost-service.yaml
+++ b/ch3.6.1/manifests/mattermost/mattermost-service.yaml
@@ -3,7 +3,7 @@ kind: Service
 metadata:
   creationTimestamp: null
   labels:
-    app: mattermost
+    run: mattermost # コマンドで作成すると run となる
   name: mattermost
 spec:
   ports:
@@ -11,7 +11,7 @@ spec:
     protocol: TCP
     targetPort: 8065
   selector:
-    app: mattermost
+    run: mattermost # コマンドで作成すると run となる
   type: NodePort
 status:
   loadBalancer: {}

ここは、app で実施するように修正する

マニュフェストを適用する

マニュフェスト適用
$ kubectl apply -f mattermost-service.yaml
service/mattermost created

マニュフェストの適用を確認

適用されたマニュフェストの確認
$ kubectl get svc mattermost -o wide
NAME         TYPE       CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE     SELECTOR
mattermost   NodePort   10.108.64.60   <none>        8065:32020/TCP   2m10s   app=mattermost

アクセス確認

以前は localhost で接続していたけど、名前で接続してみたいと思ったので、名前を確認

/etc/hosts
##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1   localhost
255.255.255.255 broadcasthost
::1             localhost
# Added by Docker Desktop
# To allow the same kube context to work on the host and the container:
127.0.0.1 kubernetes.docker.internal
# End of section

動作確認

スクリーンショット 2020-04-25 16.54.03.png

次は 3.6.2 章をやっていきます。

写経しながら「外部 LoadBalancer を使って公開する」をやっていきます

最後に

https://github.com/kubernetes-practical-guide/examples/tree/master/ch3.6.1/manifests/mattermost

今回は GitHub のマニュフェストを確認しながら行ったのですが・・・
自分のちから不足からかうまく動かなかったので、mattermost-preview のコンテナを使って
やってみました。

ここらへんのデバッグも自分でできるようになりたいと思いました。

今までの投稿

  1. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)Pod編
  2. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)NameSpace 編
  3. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)Label 編
  4. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)ReplicaSet 編
  5. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)Deployment 編
  6. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)Service 編
  7. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)ConfigMap 編
  8. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)Secret 編
  9. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)操作編
  10. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)体感編
  11. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)体感編パート2
  12. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)体感編パート3(Label操作)
  13. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)体感編パート3(OwnerReference 操作)
  14. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)マニュフェスト編
  15. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)マニュフェスト(ConfigMap)編
  16. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)通信編
  17. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)通信編 パート2
  18. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)通信編 パート3
  19. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)通信編 パート4
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)通信編 パート4

背景

個人的にインフラの知識以上にこれからのアプリケーションが動く環境を作ってデプロイしたりしてこれからの知識を身に着けたい。そしてより一層、自分の知識のアップデートをしたいと思いました。

その中でこの本に出会い、これから少しずつやったことを残し、未来の自分への手紙としてもあり、見つめ直せればと思いました。

引用や参考と今回の自分の勉強用の書籍の紹介

技術評論社『Kubernetes実践入門』のサンプルコード
Kubernetes実践入門 プロダクションレディなコンテナ&アプリケーションの作り方

実際の学びについて

書籍を読みながら、章ごとに少しずつ進めていきたいと思います。
GitHub のソースコードも使いながら学んで行きたいと思います。
この章の勉強は本当に書籍の写経が主になるかもしれません・・・

勉強開始

  • ClusterIP を使わない Headless Service を学びます
    1. 外部アプリケーションに接続する Service
    2. Service 名から各 Pod の IP アドレスを直接名前解決する Service

\2. は StatefulSet で学べるっぽい

$ cat <<EOF | kubectl create -f -
apiVersion: v1
kind: Service
metadata:
  name: headless-test
spec:
  clusterIP: None
  ports:
  - name: http
    port: 8086
    protocol: TCP
    targetPort: 8086
  selector:
    app: mattermost
EOF
service/headless-test created
$ kubectl run -i --rm test4 --image=k8spracticalguide/busybox:1.28 --restart=Never -- nslookup headless-test
If you don't see a command prompt, try pressing enter.
Error attaching, falling back to logs:
nslookup: can't resolve 'headless-test'
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

pod "test4" deleted

なんかうまく行かない・・・・

$ kubectl get po --show-labels mattermost-797c548f48-8rxwn
NAME                          READY   STATUS    RESTARTS   AGE   LABELS
mattermost-797c548f48-8rxwn   1/1     Running   0          17h   pod-template-hash=797c548f48,run=mattermost
headless-test.yamlを修正
$ kubectl edit service headless-test
〜省略〜
  selector:
-    app: mattermost
+    run: mattermost # label を run に変更

もう一度名前解決できるか確認

名前解決できた

$ kubectl run -i --rm test4 --image=k8spracticalguide/busybox:1.28 --restart=Never -- nslookup headless-test
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      headless-test
Address 1: 10.1.0.212 10-1-0-212.headless-test.default.svc.cluster.local
pod "test4" deleted

次は 3.6 章をやっていきます。

写経しながら「アプリケーションを外部に公開する」を学んでいきます

最後に

Kubernetes はやっぱり Label が重要だということを改めて実感しました
書籍でも Label で紐付けているとは記載されていますが、やってみて実感してアーキテクチャを感じることができました。

やっぱり、手を動かし、それが、自然と身につき、初めて、コマンドラインで機械と会話ができるって実感しました

今までの投稿

  1. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)Pod編
  2. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)NameSpace 編
  3. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)Label 編
  4. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)ReplicaSet 編
  5. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)Deployment 編
  6. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)Service 編
  7. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)ConfigMap 編
  8. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)Secret 編
  9. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)操作編
  10. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)体感編
  11. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)体感編パート2
  12. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)体感編パート3(Label操作)
  13. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)体感編パート3(OwnerReference 操作)
  14. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)マニュフェスト編
  15. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)マニュフェスト(ConfigMap)編
  16. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)通信編
  17. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)通信編 パート2
  18. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)通信編 パート3
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

パッケージマネージャーを利用して Windows に docker-cli を導入する

Windows が標準で備えるパッケージマネジメント機能を利用し、下記の Docker CLI ツールを導入します。

Chocolatey Software | Docker CLI 19.03.3

検証環境:

PS > $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.18362.752
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.18362.752
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

ここでは PowerShell Core ではなく、Windows PowerShell を利用しています。

パッケージプロバイダの追加

Windows PowerShell を管理者権限で起動し、利用可能なパッケージプロバイダを確認します。

PS > Find-PackageProvider

Name                           Version          Source           Summary
----                           -------          ------           -------
nuget                          2.8.5.208        https://onege... NuGet provider for the OneGet meta-package manager
psl                            1.0.0.210        https://onege... psl provider for the OneGet meta-package manager
chocolatey                     2.8.5.130        https://onege... ChocolateyPrototype provider for the OneGet meta-pa...
PowerShellGet                  2.2.4.1          PSGallery        PowerShell module with commands for discovering, in...
DockerMsftProvider             1.0.0.8          PSGallery        PowerShell module with commands for discovering, in...
DockerProvider                 0.0.0.3          PSGallery        PowerShell module with commands for discovering, in...
ContainerImage                 0.6.4.0          PSGallery        This is a PackageManagement provider module which h...
ChocolateyGet                  1.0.0.1          PSGallery        An PowerShell OneGet provider that discovers packag...
NanoServerPackage              1.0.1.0          PSGallery        A PackageManagement provider to  Discover, Save and...
GitLabProvider                 1.3.8            PSGallery        GitLab PackageManagement provider
DockerMsftProviderInsider      1.0.0.2          PSGallery        PowerShell module with commands for discovering, in...
GistProvider                   0.6              PSGallery        Gist-as-a-Package - PackageManagement  PowerShell P...
GitHubProvider                 0.5              PSGallery        GitHub-as-a-Package - PackageManagement PowerShell ...
0install                       2.17.2           PSGallery        OneGet Package Provider for Zero Install
TSDProvider                    0.2              PSGallery        PowerShell PackageManager provider to search & inst...
OfficeProvider                 1.0.0.1          PSGallery        OfficeProvider allows users to install Microsoft Of...
AppxGet                        0.1.0.1          PSGallery        Powershell Package Management (OneGet) Provider for...
MyAlbum                        0.1.2            PSGallery        MyAlbum provider discovers the photos in your remot...
WSAProvider                    1.0.0.4          PSGallery        Provider to Discover, Install and inventory windows...
ChocoOneGet                    0.4.0            PSGallery        OneGet provider for Chocolatey
Chocolatier                    1.0.4            PSGallery        Package Management (OneGet) provider that facilitat...
Pacman-Provider                0.0.1            PSGallery        Pacman provider enables installation of pacman pack...

これらプロバイダのうち、今回は ChocolateyGet を利用します。

Install-PackageProvider コマンドにより、このプロバイダを追加します。

PS > Install-PackageProvider ChocolateyGet -Force

Name                           Version          Source           Summary
----                           -------          ------           -------
ChocolateyGet                  1.0.0.1          PSGallery        An PowerShell OneGet provider that discovers packag...

Docker CLI ツールの導入

まず、プロバイダにパッケージが登録されているか確認します。

PS > Find-Package docker-cli -ProviderName ChocolateyGet

Name                           Version          Source           Summary
----                           -------          ------           -------
docker-cli                     19.03.3          https://www.c...

パッケージをインストールするには、Install-Package コマンドを利用します。

PS > Install-Package docker-cli -ProviderName ChocolateyGet -Force

Name                           Version          Source           Summary
----                           -------          ------           -------
docker-cli                     v19.03.3         https://www.c...

インストールが完了すると、以下の通り docker コマンドが利用可能になります。

PS > docker version
Client:
 Version:           19.03.3
 API version:       1.40
 Go version:        go1.12.10
 Git commit:        2355349d-
 Built:             10/14/2019 16:41:26
 OS/Arch:           windows/amd64
 Experimental:      false
error during connect: Get http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.40/version: open //./pipe/docker_engine: The system cannot find the file specified. In the default daemon configuration on Windows, the docker client must be run elevated to connect. This error may also indicate that the docker daemon is not running.

Docker のデーモンが起動していないためエラーメッセージが出力されていますが、リモートの Docker ホスト等に接続すればローカルで実行する場合と同様に Docker を利用できると思います。

参考:

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

Dockerのproduction環境でのbundle exec方法

DockerでRailsをする時にProduction環境でdb:createができずに調べてもなかなか情報が出てこなかったのでメモ。docker exec-eオプションで環境変数をセットしてコンテナ内部のコマンドを呼べます。

docker exec -e RAILS_ENV='production' myapp bundle exec rake db:create

参考

https://devconnected.com/docker-exec-command-with-examples/

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

Dockerでの環境構築(Rails)超入門1

はじめに

Ruby on Rails初心者です。今回はDockerを使ったRailsの環境構築の初歩を勉強のために備忘録として残したいと思います。

前提

DockerでRailsの開発環境を行う
※あくまで開発環境を構築するためだけの超入門であるため、DBや細かい設定等は次回以降投稿する

次回

Dockerでの環境構築(Rails)超入門2 ~Dockerfileの設定~

手順

Dockerはインストールしていることが前提
1. Dockerfile, docker-compose.yamlの作成
2. Dockerのコンテナを起動
3. Railsの設定
4. Node.jsの設定
5. Yarnのインストール

実践

  1. Dockerfile, docker-compose.yamlの作成

・ディレクトリを作成(今回はDocker/practice)

$  cd Desktop
$ mkdir docker
$ mkdir practice
$ cd practice

・Docker hubで「ruby」を検索し、バージョンを確認

・Dockerfile作成

FROM ruby:2.6.6-stretch

・docker-compose.yaml作成

version: '3'
services:
  app:
    build: .
    volumes:
      - ".:/app"
    ports:
      - "3000:3000"
    tty: true
  1. Dockerのコンテナを起動
$ docker-compose up

 下記が表示されればOK!

(省略)
Creating practice_app_1 ...  done
Attaching to practice_app_1
(省略)

・practice_app_1の中に入る

$ docker exec -it practice_app_1 /bin/bash

# Appがローカルになっているので
/# cd app/

3.Railsの設定

/# gem install rails

/# rails new

# ローカルに接続
/# rails s -b 0.0.0.0

・ローカルに接続したら下記のエラーが出た

# エラー「Please run rails webpacker:install」
/#  rails webpacker:install

# エラー 
Webpacker requires Node.js >= 6.14.4 and you are using 4.9.1
Please upgrade Node.js https://nodejs.org/en/download/

4.Node.jsの設定

・そのためNode.jsをアップデートする

# Node.jsのバージョン管理ツールnvmをclone
$ git clone git://github.com/creationix/nvm.git ~/.nvm
$ echo . ~/.nvm/nvm.sh >> ~/.bashrc
$ . ~/.bashrc

# nvmバージョン確認
$ nvm --version
0.35.3


# 最新の安定版をインストール
$ nvm install stable

# バージョン確認
$ node -v
v14.0.0

# 再度試す
$ rails webpacker:install 
Yarn not installed. Please download and install Yarn from https://yarnpkg.com/lang/en/docs/install/

↑Yarnのインストールが必要とのこと、、

5.Yarnのインストール
・node.jsをインストールするとnpmが入っているはずなので以下のコマンドを実行する

# node.jsのバージョンを確認
node -v
# npmのバージョンを確認
npm -v


# npm 経由でyarnをインストール
npm install -g yarn
# yarnのバージョンを確認
yarn -v

/app# yarn install

/app# rails webpacker:install

# 成功
Webpacker successfully installed ? ?

# ローカルに接続
/app# rails s -b 0.0.0.0

# エラー
error Couldn't find an integrity file
error Found 1 errors.


========================================
  Your Yarn packages are out of date!
  Please run `yarn install --check-files` to update.
========================================

↑言われた通りコマンドを実行

/app# yarn install --check-files

# 再度接続
/app# rails s -b 0.0.0.0

・下記の画面が出ればOK!

スクリーンショット 2020-04-25 12.37.24.png

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

Dockerでの環境構築(Rails)超入門

はじめに

Ruby on Rails初心者です。今回はDockerを使ったRailsの環境構築の初歩を勉強のために備忘録として残したいと思います。

前提

DockerでRailsの開発環境を行う
※あくまで開発環境を構築するためだけの超入門であるため、DBや細かい設定等は次回以降投稿する

手順

Dockerはインストールしていることが前提
1. Dockerfile, docker-compose.yamlの作成
2. Dockerのコンテナを起動
3. Railsの設定
4. Node.jsの設定
5. Yarnのインストール

実践

  1. Dockerfile, docker-compose.yamlの作成

・ディレクトリを作成(今回はDocker/practice)

$  cd Desktop
$ mkdir docker
$ mkdir practice
$ cd practice

・Docker hubで「ruby」を検索し、バージョンを確認

・Dockerfile作成

FROM ruby:2.6.6-stretch

・docker-compose.yaml作成

version: '3'
services:
  app:
    build: .
    volumes:
      - ".:/app"
    ports:
      - "3000:3000"
    tty: true
  1. Dockerのコンテナを起動
$ docker-compose up

 下記が表示されればOK!

(省略)
Creating practice_app_1 ...  done
Attaching to practice_app_1
(省略)

・practice_app_1の中に入る

$ docker exec -it practice_app_1 /bin/bash

# Appがローカルになっているので
/# cd app/

3.Railsの設定

/# gem install rails

/# rails new

# ローカルに接続
/# rails s -b 0.0.0.0

・ローカルに接続したら下記のエラーが出た

# エラー「Please run rails webpacker:install」
/#  rails webpacker:install

# エラー 
Webpacker requires Node.js >= 6.14.4 and you are using 4.9.1
Please upgrade Node.js https://nodejs.org/en/download/

4.Node.jsの設定

・そのためNode.jsをアップデートする

# Node.jsのバージョン管理ツールnvmをclone
$ git clone git://github.com/creationix/nvm.git ~/.nvm
$ echo . ~/.nvm/nvm.sh >> ~/.bashrc
$ . ~/.bashrc

# nvmバージョン確認
$ nvm --version
0.35.3


# 最新の安定版をインストール
$ nvm install stable

# バージョン確認
$ node -v
v14.0.0

# 再度試す
$ rails webpacker:install 
Yarn not installed. Please download and install Yarn from https://yarnpkg.com/lang/en/docs/install/

↑Yarnのインストールが必要とのこと、、

5.Yarnのインストール
・node.jsをインストールするとnpmが入っているはずなので以下のコマンドを実行する

# node.jsのバージョンを確認
node -v
# npmのバージョンを確認
npm -v


# npm 経由でyarnをインストール
npm install -g yarn
# yarnのバージョンを確認
yarn -v

/app# yarn install

/app# rails webpacker:install

# 成功
Webpacker successfully installed ? ?

# ローカルに接続
/app# rails s -b 0.0.0.0

# エラー
error Couldn't find an integrity file
error Found 1 errors.


========================================
  Your Yarn packages are out of date!
  Please run `yarn install --check-files` to update.
========================================

↑言われた通りコマンドを実行

/app# yarn install --check-files

# 再度接続
/app# rails s -b 0.0.0.0

・下記の画面が出ればOK!

スクリーンショット 2020-04-25 12.37.24.png

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

Win10HomeのDockerでJupyterLab環境を整える

概要

仮想環境ソフトウェアDockerを使うことで、OSに関係なく計算環境を構築・移行することが出来ます。Win10HomeでJupyterLab環境を構築する手順を示します。このJupyterLab環境では、Python, R, Juliaを使うことが出来ます。

各用語の説明

  • 仮想環境 : ハードウェアやOSの異なる環境でも動作する仕組みのこと。これにより、ハードウェアやOSに依存せずに環境を動作させることが可能。
  • Docker : 仮想環境ソフトウェアの一つ。「コンテナ」という仕組みを採用しており、従来の仮想環境ソフトウェアと比較し軽量であるのが特徴。オープンソース。
  • Dockerhub : 様々なDocker環境がアップロードされているサーバー兼ウェブサイト。たった1つのコマンドでDocker環境を構築することが出来る。
  • JupyterLab : Python, R, Juliaなどの言語をインタラクティブに実行出来る計算環境。ブラウザベースで動作するため、仮想環境ソフトウェアで簡単に構築することが出来る。今回はDockerhubにアップロードされているJupyter公式のDocker環境を用いる。

手順

  1. Windows 10 Insider Preview ビルドをインストールする
    Windows Insider Program ユーザー ガイド - Microsoft
  2. Docker Desktop Edge 2.2.2.0をインストールする
    Docker Desktop for Windows Home is here! - docker official blog
  3. PowerShellでdockerコマンドが正常に動くことを確認する
  4. メニューバーのDockerアイコンを右クリックして「Linux containers」に切り替える
    image.png
  5. メニューバーのDockerアイコンを右クリックして「設定」を選択する。Dockerと共有したいドライブにチェックを入れておく。この場合はCドライブにもDドライブにもチェックを入れておけば良い
  6. Powershellで以下のコマンドを走らせる。以下では共有先ディレクトリにd:/Desktopで「DドライブのDesktop」を指定している。各自の環境に合わせて適宜変更する。
    docker run -d --restart always -p 10000:8888 -e JUPYTER_ENABLE_LAB=yes -v d:/Desktop:/home/jovyan/work --name notebook jupyter/datascience-notebook jupyter-lab --NotebookApp.token='' --allow-root
  7. 以下のURLにアクセスする
    http://localhost:10000
  8. 正常に起動できれば、以下のように表示される。①workフォルダ以下にデスクトップのファイルが表示される。②各言語のnotebookを作成することが出来る。③conda install (ライブラリ名)のようにライブラリをインストールすることが出来る

参考URL

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

Win10HomeのDockerでJupyterLab環境を構築する

概要

仮想環境ソフトウェアDockerを使うことで、OSに関係なく計算環境を構築・移行することが出来ます。Win10HomeでJupyterLab環境を構築する手順を示します。このJupyterLab環境では、Python, R, Juliaを使うことが出来ます。

各用語の説明

  • 仮想環境 : ハードウェアやOSの異なる環境でも動作する仕組みのこと。これにより、ハードウェアやOSに依存せずに環境を動作させることが可能。
  • Docker : 仮想環境ソフトウェアの一つ。「コンテナ」という仕組みを採用しており、従来の仮想環境ソフトウェアと比較し軽量であるのが特徴。オープンソース。
  • Dockerhub : 様々なDocker環境がアップロードされているサーバー兼ウェブサイト。たった1つのコマンドでDocker環境を構築することが出来る。
  • JupyterLab : Python, R, Juliaなどの言語をインタラクティブに実行出来る計算環境。ブラウザベースで動作するため、仮想環境ソフトウェアで簡単に構築することが出来る。今回はDockerhubにアップロードされているJupyter公式のDocker環境を用いる。

手順

  1. Windows 10 Insider Preview ビルドをインストールする
    Windows Insider Program ユーザー ガイド - Microsoft
  2. Docker Desktop Edge 2.2.2.0をインストールする
    Docker Desktop for Windows Home is here! - docker official blog
  3. PowerShellでdockerコマンドが正常に動くことを確認する
  4. メニューバーのDockerアイコンを右クリックして「Linux containers」に切り替える
    image.png
  5. メニューバーのDockerアイコンを右クリックして「設定」を選択する。Dockerと共有したいドライブにチェックを入れておく。この場合はCドライブにもDドライブにもチェックを入れておけば良い
  6. Powershellで以下のコマンドを走らせる。以下では共有先ディレクトリにd:/Desktopで「DドライブのDesktop」を指定している。各自の環境に合わせて適宜変更する。
    docker run -d --restart always -p 10000:8888 -e JUPYTER_ENABLE_LAB=yes -v d:/Desktop:/home/jovyan/work --name notebook jupyter/datascience-notebook jupyter-lab --NotebookApp.token='' --allow-root
  7. 以下のURLにアクセスする
    http://localhost:10000
  8. 正常に起動できれば、以下のように表示される。①workフォルダ以下にデスクトップのファイルが表示される、②各言語のnotebookを作成、③conda install (ライブラリ名)コマンドで各ライブラリをインストール

参考URL

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

ansibleでkubernetes環境の構築 2

はじめに

前回の記事でansibleを使用してkubernetesを初期化することができた
いよいよk8s workerを追加して本確定なk8s環境を作っていく

環境

MBP OS Sierra
MAASサーバー(192.168.100.152 MAAS用ネットワーク:192.168.200.1)
k8s-masterサーバー(KVM:192.168.100.191)
ansibleサーバー(KVM:192.168.100.192)
k8s worker(192.168.200.151)
k8s worker(192.168.200.153)

dash-board Ver.1.8

ゴール

k8sで作ったflannelネットワーク内に、MAASでOSをデプロイしたマシンをk8s-workerとして追加する
またk8sの使用状況をダッシュボードでも見ることができるようにする

MAASサーバーのネットワーク設定

今回はMAASのDHCP問題の関係でk8s-masterとworkerは別のネットワークにしているため、MAASサーバーでブリッジ設定をする必要がある

ubuntu18は16までのものとネットワーク設定の仕方が変わっている
/etc/netplan/50-cloud-init.yaml_bkの記述だけでいけるはずだったが、ブリッジの設定がうまくいかなかったため今回は2種類のファイルに記述している

$ sudo vi /etc/netplan/50-cloud-init.yaml_bk
network:
    ethernets:
        enp0s31f6:
            addresses:
            - 192.168.100.152/24
            gateway4: 192.168.100.1
            nameservers:
                addresses:
                - 8.8.8.8
                search:
                - 8.8.4.4
        enp2s0:
            addresses:
            - 192.168.200.1/24
            gateway4: 192.168.100.1
            nameservers:
                addresses:
                - 8.8.8.8
                search:
                - 8.8.4.4
    version: 2

$ sudo vi /etc/network/interfaces
auto lo
iface lo inet loopback

auto enp0s31f6
iface enp0s31f6 inet manual

auto br0
iface br0 inet static
address 192.168.100.152
netmask 255.255.255.0
gateway 192.168.100.1
dns-nameservers 8.8.8.8
bridge_ports enp0s31f6
bridge_maxwait 0
bridge_df 0
bridge_stp off


auto enp2s0
iface enp2s0 inet static
address 192.168.200.1
netmask 255.255.255.0
gateway 192.168.100.1
dns-nameservers 8.8.8.8

$ ifconfig
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.100.152  netmask 255.255.255.0  broadcast 192.168.100.255
        inet6 fe80::329c:23ff:feac:5570  prefixlen 64  scopeid 0x20<link>
        ether 30:9c:23:ac:55:70  txqueuelen 1000  (Ethernet)
        RX packets 9579059  bytes 16579553543 (16.5 GB)
        RX errors 0  dropped 657286  overruns 0  frame 0
        TX packets 6047022  bytes 936298283 (936.2 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

enp0s31f6: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::329c:23ff:feac:5570  prefixlen 64  scopeid 0x20<link>
        ether 30:9c:23:ac:55:70  txqueuelen 1000  (Ethernet)
        RX packets 21689196  bytes 26237413396 (26.2 GB)
        RX errors 0  dropped 475  overruns 0  frame 0
        TX packets 6555651  bytes 4057603928 (4.0 GB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        device interrupt 16  memory 0xdf100000-df120000

enp2s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.200.1  netmask 255.255.255.0  broadcast 192.168.200.255
        inet6 fe80::6a05:caff:fe66:a834  prefixlen 64  scopeid 0x20<link>
        ether 68:05:ca:66:a8:34  txqueuelen 1000  (Ethernet)
        RX packets 6867754  bytes 970026556 (970.0 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 13304857  bytes 15246678579 (15.2 GB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        device interrupt 17  memory 0xdf0c0000-df0e0000

また2つのネットワークで通信できるようにNATの設定をする

sudo iptables -t nat -A POSTROUTING -s 192.168.200.0/24 -j SNAT --to 192.168.100.152

workerの追加

k8sのworkerを追加するにはマスターの場合とほとんど変わらないがflannelネットワークに参加させる最後に起動させるコマンドが必要になる

そのコマンドはkubeadm initを行なった際の出力内容に表示されるが、下記コマンドでも確認することができる

(k8s-master)$ kubeadm token create --print-join-command

出てきたコマンドを使ってworker参加用のplaybookを作成する

(ansible)$ sudo vi mlp.yml
---
- hosts: mlp01
  remote_user: ubuntu
  become: yes
  tasks:
    - name: Install prerequisites and Docker.io , nfs-common
      apt: name={{item}} update_cache=yes
      with_items:
        - nfs-common
        - apt-transport-https
        - ca-certificates
        - curl
        - software-properties-common
        - docker.io
    - name: user add to docker group
      user: name=ubuntu group=docker append=yes
    - name: Add K8S GPG key
      apt_key:
        url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
    - name: Add K8S APT repository
      apt_repository:
        repo: deb http://apt.kubernetes.io/ kubernetes-xenial main
    - name: Install K8S
      apt: name={{item}} update_cache=yes
      with_items:
        - kubelet
        - kubeadm
        - kubectl
    - name: Remove swapfile from /etc/fstab
      mount:
        name: swap
        fstype: swap
        state: absent
    - name: Disable swap
      command: swapoff -a
      when: ansible_swaptotal_mb > 0
    - name: Set docker service to start on boot.
      service: name=docker enabled=yes
    - name: Set kubelet service to start on boot.
      service: name=kubelet enabled=yes
    - name: Join k8s-master
      become: yes
      shell: kubeadm join 192.168.100.191:6443 ~~ #上記のコマンドで出力したものを記述

マスターの時と同様にhostsの編集

$ sudo vi /etc/ansible/hosts
[master]
k8s-master

[mlp]
mlp01 

$ sudo vi /etc/hosts 
192.168.100.191 k8s-master 192.168.200.151 mlp01 

ansibleのplaybook実行
python3をしようする場合は"-e"以降のオプションが必要

~/ansible$ sudo ansible-playbook --private-key=id_rsa_common mlp.yml -e 'ansible_python_interpreter=/usr/bin/python3'

playbookが成功した場合、以下の状態になる

(k8s-master)$ kubectl get node
NAME         STATUS    ROLES     AGE       VERSION
k8s-master   Ready     master    3d        v1.10.3
mlp01        Ready     <none>    3d        v1.10.2

nginxイメージの起動

nodeが追加された後は、ひとまずnginxのdockerイメージを走らせる
理由は後述する

$ sudo vi nginx-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
    - name: nginx-container
      image: nginx
      ports:
      - containerPort: 80

$ kubectl apply -f nginx-pod.yaml
create
$ kubectl get pod
NAME           READY     STATUS    RESTARTS   AGE
nginx-pod      1/1       Running   0          3d

nginxがRunningになれば問題ない

Dash-boardのインストール

Dash-boardはなくても、kubernetesを使う上ではなんとかなるがせっかくなら使いたい
というわけでインストールをしていく

$ kubectl create -f https://raw.githubusercontent.com/kubernetes/dashboard/master/src/deploy/recommended/kubernetes-dashboard.yaml

エラーが出ず、「created」と表示されればOK
動いているかを確認

kubectl get pods --all-namespaces
NAMESPACE     NAME                                    READY     STATUS    RESTARTS   AGE
default       nginx-pod                               1/1       Running   0          3d
kube-system   kubernetes-dashboard-7d5dcdb6d9-7hptz   1/1       Running   0          3d

kubeのproxyを起動

$ kubectl proxy --address 0.0.0.0 --accept-hosts '.*'
Starting to serve on [::]:8001

この状態になったらブラウザでアクセスして見る
ログイン画面が出てくる

http://localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/#!/login
スクリーンショット 2018-05-29 14.24.06.png

ログインするためのトークンを発行する

$ kubectl -n kube-system get secret

発行されたトークンを使えば入れる

毎回トークンを発行するのが大変という人向けの設定は以下のもの
これを実行した後は、ログイン画面のSKIPで入れるようになる
ただしセキュリティ的にはガバガバなため、社内オンリーの環境など外部の人がいない条件での使用推奨

$ cat <<EOF | kubectl create -f -
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: kubernetes-dashboard
  labels:
    k8s-app: kubernetes-dashboard
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: kubernetes-dashboard
  namespace: kube-system
EOF

これでkubernetesの環境構築は終了である

おわりに

この環境を作ることができたら、あとはk8s-masterからdockerイメージを起動させればnodeに自動配布することができる
nodeの新規追加もflannelネットワークに追加するコマンドさえあればすぐできるためとても便利

つまづいたところ

ネットワーク通信

この記事の冒頭の方でネットワーク設定を載せているが、これに決まるまでは通信が通らないエラーがで続けていた
ubuntu18のバージョン変更に伴う設定方法の変更に振り回された印象

kubeadm initが失敗する

原因としてはswapの消去を忘れていただけだが、存在を忘れがちである

dash-boardが表示されない

マスターにノードが追加され、dash-boardをインストール→proxyを起動としただけではブラウザにdash-boardは表示されず、ブラウザのページにはファイルのディレクトリツリーだけが出てくるのみだった
試しにページの中段にあるようにproxy-podを起動させてみて、その後手順通りに進めたらdash-boardが表示されるようになった
他の参考にしたページでは同様の症状はなかったようでdash-boardのバージョンの仕様なのか、自分だけだやっていない設定があるのか、原因は不明

参考にしたページ

iptables で NAT 環境を構築してみた
kubernetes 公式ページ
access control
Kubernetes/Web UI (Dashboard)の追加
KubernetesにDashboardをインストールして、認証なしでアクセスする

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

ansibleでkubernetes環境の構築 1

はじめに

nodeに対してのk8sのインストールなどは極力ansibleで自動化していく
ansibleの実行機やk8sのマスターはMAASサーバーのKVMを使用する

ゴール

ansibleでk8sをインストールできる状態まで構築する

環境

MBP OS Sierra
MAASサーバー(192.168.100.152)
k8s-masterサーバー(KVM:192.168.100.191)
ansibleサーバー(KVM:192.168.100.192)

ansible Ver.2.5.1
kubernetes Ver.1.10.3

MAASサーバーにKVMをインストールする

ansibleサーバー、k8sサーバーを作るためのKVMを土台となるMAASサーバーにインストールする
インストール後はlibvirtグループに参加し、sudoなしでも実行できるようにする

$ sudo apt install -y qemu-kvm libvirt0 libvirt-bin virt-manager bridge-utils
$ sudo systemctl enable libvirt-bin
$ sudo gpasswd libvirtd -a <username>

KVMの作成はデスクトップ環境を使用した方が便利なため、MAASサーバーにデスクトップをインストールする

$ sudo apt -y install ubuntu-desktop

デスクトップのインストールは時間がかかるためしばし待つ
インストールが完了して再起動すれば自動でデスクトップが表示される

デスクトップ上のターミナルでKVMを起動すれば作成用ウィンドウが起動される

$ virt-manager
0001_New-Virtual-Machine.png

ここで下記スペックのKVMを新規作成する

ホスト名:ansible
メモリ:4GB
CPU:2
ストレージ:30GB

ホスト名:k8s-master
メモリ:8GB
CPU:4
ストレージ:40GB

ansibleの構築

KVMで作成したansibleサーバーに実際にansibleをインストールする

$ sudo apt-get update
$ sudo apt-get install software-properties-common
$ sudo apt-add-repository ppa:ansible/ansible
$ sudo apt-get update
$ sudo apt-get install ansible

今回はhome直下にansibleフォルダを作成し、各種ファイルを管理する

$ sudo mkdir ansible

k8s-masterにk8sをインストールするためのplaybookを作成する

$ sudo vi k8s-master.yaml

---
- hosts: k8s-master
  remote_user: $user名
  become: yes
  tasks:
    - name: Install prerequisites and Docker.io #dockerインストール
      become: yes
      apt: name={{item}} update_cache=yes
      with_items:
        - apt-transport-https
        - ca-certificates
        - curl
        - software-properties-common
        - docker.io
    - name: user add to docker group
      user: name=gauss group=docker append=yes
    - name: Add K8S GPG key #k8sインストール準備
      apt_key:
        url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
    - name: Add K8S APT repository
      apt_repository:
        repo: deb http://apt.kubernetes.io/ kubernetes-xenial main
    - name: Install K8S
      apt: name={{item}} update_cache=yes
      with_items:
        - kubelet
        - kubeadm
        - kubectl
    - name: Remove swapfile from /etc/fstab #swapを消しておかないと失敗する
      mount:
        name: swap
        fstype: swap
        state: absent
    - name: Disable swap
      command: swapoff -a
      when: ansible_swaptotal_mb > 0
    - name: Set docker service to start on boot. #再起動後もdockerを自動起動させる
      service: name=docker enabled=yes
    - name: Set kubelet service to start on boot. #再起動後もk8sを自動起動させる
      service: name=kubelet enabled=yes
    - name: Init k8s-master #k8smの初期化
      become: yes
      shell: kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=192.168.100.191
    - name: Make Directory .kube
      file:
        path: /.kube
        state: directory
        owner: $オーナー
        group: docker
        mode: 0755
    - name: Copy the .kube config
      become: yes
      file:
        src: /home/$ユーザ名/ansible/admin.conf
        dest: ~/.kube/config
        owner: $オーナー
        group: docker
        mode: 0600
    - name: Export Kubernetes
      lineinfile:
        path: /home/$ユーザ名/.kube/config
        state: absent
        regexp: '^%KUBECONFIG'
    - name: Apply Flannel $flannelのネットワークを作成
      sudo: yes
      shell: kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/v0.10.0/Documentation/kube-flannel.yml

次はansibleのhostsを追加設定

$ sudo vi /etc/ansible/hosts
[master]

k8s-master $ sudo vi /etc/hosts 192.168.100.191 k8s-master

準備ができたらansibleのplaybook実行
python3をしようする場合は"-e"以降のオプションが必要

~/ansible$ sudo ansible-playbook --private-key=id_rsa_common k8s-master.yml -e 'ansible_python_interpreter=/usr/bin/python3'

エラーが出なければ完了

おわりに

k8sはバージョンの移り変わりが早く、ubuntuも18.04と新しいバージョンでエラーが多くどうなるかと思ったが初期化の成功にひとまず安心した

つまづいたところ

dockerのバージョン

k8sの初期化をする際、最新のdocker(18.03)を入れていると、対応しているバージョンは17.03までだからダウングレードしろとメッセージが出たため、17.03を入れ直した
しかし失敗するのは変わらなかったため、docker.ioをいれたところ成功した

kube-dnsが機能しなかった

ansibleファイル内で実行しているkubeadm initのコマンドにおいて、--pod-network-cidrのネットワーク表記を当初「10.0.0.0」にしていたが、その設定だとパッケージに入っているkube-dnsが機能しなかった
各ページを確認したところこのネットワークは「10.244.0.0」が正しそうだということがわかり、そちらの設定でコマンドを実行したところ正常にkube-dnsは機能してくれた

続き→ansibleでkubernetes環境の構築 2

参考ページ

Ubuntu 16.04: KVMをインストールして仮想マシンを起動する
Ansible入門しました。【入門編】
kubernetes 公式ページ
kubernetesによるDockerコンテナ管理入門
kubeadm で kubernetes v1.8 + Flannel をインストール

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

0から始めるUbuntu18.04+MAAS2.4環境作成

はじめに

現在社内でMAAS+kubernetes環境を構築しようというプロジェクトがあり、
その中で行ったもの、つまづいたところを記述していく.

ゴール

Ubuntuでサーバーを構築し、独立したネットワーク内でUbuntuOSのデプロイをPXEブート経由でできるようになる.

導入前注意事項

MAASサーバーが存在するネットワークにはDHCPが存在しないことを事前に確認する.
DHCPが既存のネットワークでMAASサーバーを構築すると、後の設定でMAASサーバーがDHCPサーバーになるため、既存DHCPと競合する.
DHCPが競合すると、ネットワーク内の端末がIPアドレスを再取得する際にMAASサーバーから取得した場合、ネットワークの外側と通信できなくなる.
また、MAASクライアントになるはずの端末も、MAASサーバーと安定的に通信できなくなる.
(様々な記事を確認したが現状未解決)

構築用端末

MAASサーバー用端末(IP:192.168.200.1)
MAASクライアント用端末(IP:192.168.200.151)
macbookpro

Ubuntuインストール

ubuntuダウンロード

以下のURLからUbuntu ServerのISOイメージをダウンロードする.

http://releases.ubuntu.com/18.04/

Ubuntuイメージの起動ディスク作成

手持ちのUSBメモリにUbuntuのISOイメージを焼き付けて、インストール用メディアを作成する.

USBメモリの確認

MACにUSBメモリを差した後、ターミナルを立ち上げディスクの場所を確認する.

diskutil list
スクリーンショット 2018-05-20 19.18.13.png

コマンド実行時はUSBメモリは/dev/disk2となっていたので、これを一度MS-DOS形式でフォーマットする.

diskutil eraseDisk MS-DOS UNTITLED /dev/disk2

フォーマットされたUSBメモリをアンマウントしddコマンドで起動ディスクを作成する.

diskutil unmountDisk /dev/disk2
sudo dd if=./Downloads/ubuntu-18.04-live-server-amd64.iso of=/dev/disk2 bs=4028

多少時間がかかるため、コーヒータイム.
イメージ作成が完了したら、デバイスを取り外す.

もし刺さったままなら、

diskutil eject /dev/disk2

を実行してUSBメモリを抜く.

Ubuntuイメージのインストール

MAASサーバ用の端末に先ほど作成したUSBを差し、BOOT画面でUSB起動を指定しインストールを開始.
BOOTデバイスの指定はマシンによって異なるため省略.

インストールのオプションは任意の設定で.

MAASインストール

サーバーにMAASパッケージをインストールする.

$ sudo apt -y update
$ sudo apt -y upgrade
$ sudo apt -y install maas

インストールが完了したら管理者用ユーザの作成.
必要なユーザー名、パスワード、アドレスなどを設定.
SSHキーの登録は後で行うため、空欄のままエンターでスルー.

$ sudo maas createadmin

作成が完了したら「MAASサーバーのアドレス:5240/MAAS/」でログイン.

MAASの設定

ログイン画面が出てくるため、
作成したユーザーでログイン.

スクリーンショット 2018-05-22 14.24.41.png

ログイン後、イントロページが出てくる.
特に設定をいじる必要はない.

後者の画像では、ダウンロードするUbuntuのOSイメージを選択する.
欲しいバージョンにチェックを入れたら、基本的に自動でダウンロードが始まるため、しばらく待つ.

ダウンロードが完了し、「Status」が「Synced」になったらContinueをクリック

スクリーンショット 2018-05-22 14.24.59.png スクリーンショット 2018-05-22 14.25.20.png

秘密鍵を入力する画面に移るため、Ubuntuサーバー側で鍵を生成する.
特に指定はせずに、空欄のままエンター連打.

$ sudo ssh-keygen -t rsa

サーバーの.sshフォルダに鍵が生成されるため、
そちらの公開鍵の中身をコピーする.

cat .ssh/id_rsa.pub

コピー後はMAASの管理サーバーに戻り、SourceをUploadに変え、隣の入力画面に先ほどコピーした鍵の中身をペーストし、Importをクリック.
問題がなければ「Go to dashboard」をクリック.

スクリーンショット 2018-05-22 14.25.54.png

準備として、MAASトップページ上部の「Subnets」ページ内、展開したいネットワークVLANのuntaggedを選択.

スクリーンショット 2018-05-23 12.28.03.png

画面上部の「Take action」から「Provide DHCP」を選択.

スクリーンショット 2018-05-23 12.32.09.png 68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3235393334332f64616464393437352d626531372d663134302d343534662d3738653037616661623833342e706e67.png

MAASサーバーのDHCPレンジが出てくるため、任意の数を指定し、「Provide DHCP」を選択すると、同じページ内のDHCP項目がEnableになり、「Reserved ranges」に追加したネットワーク範囲が表示される.

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3235393334332f61386132633162382d666161392d373463342d343033302d6465343265633232393032652e706e67.png

これで一通りの下準備が完了になる.

MAASクライアントのデプロイ

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3235393334332f39303965386538342d303465642d316430392d623232342d3663613962366132383333352e706e67.png

MAASクライアントとなる端末のBOOT順序でPXE bootの項目を起動順序の一位へする.
その後クライアントの電源を入れると自動でMAASサーバーと通信を開始し、電源が落ちる.
電源が落ちた後は、MAASの管理画面上の「Machines」に端末が追加される.
(端末の名前は仮で動物の名前が入る)

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3235393334332f32366162613330652d373034352d313963662d323831332d3630303036356336396365362e706e67.png

追加されたマシンを選択し、まずは名前の変更をする.

スクリーンショット 2018-05-23 16.03.41.png

「Configration」内の「Power configuration」で電源オプションを選択.
今回は「Manual」を選択する.

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3235393334332f66666561643063632d323034382d313363342d386665652d3363303734316634656464362e706e67.png

「Machines」ページで、端末のチェックボックスにチェックを入れ、「Take action」から「Commission」を選択した後、クライアント端末の電源を入れる.

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3235393334332f35316137386634322d373239632d333466652d386265312d6133303934666434366330632e706e67.png

再びサーバーとの通信を開始するので終了まで待つ.
無事にCommissionが終了したら、サーバーの管理画面では「Status」が「Ready」になる.

「Take action」から「Deploy」を選択し任意のOSを選択し、デプロイを開始させ、クライアントの電源を入れる.

68747470733a2f2f71696974612d696d6167652d73746f72652e73332e616d617a6f6e6177732e636f6d2f302f3235393334332f66633432313464632d663562382d643934382d653133302d3335616265613531353863312e706e67.png

サーバーからOSがデプロイされるため、しばし待ち、管理画面上でStatus欄がOS名に変われば成功

.

クライアント端末のネットワーク設定について

MAASのクライアント端末は基本はDHCPだが、Staticに指定することも可能.

その場合はOSのデプロイ前に端末の情報ページ内「Interfaces」内の「Actions」-「Edit Physical」を選択し、「Auto assign」を「Static」に変更し、任意のアドレスを指定する.

スクリーンショット 2018-05-22 13.54.10.png スクリーンショット 2018-05-22 13.54.26.png

つまづいたところ

MAASサーバーをインストールした後、設定画面上はDHCPはEnabledになっているが、クライアントに対してアドレスの配布が行われない.

解決方法
管理画面上部「Controllers」内の「Name」にあるマシンを選択(初期だと一つしかないはず)
移ったページ内のServices項目において「dhcpd」にグリーンマークが付いていない場合があるため、一度MAASを再起動するとグリーンマークが付くようになった.

これでもダメな場合は、

sudo dpkg-reconfigure maas-rack-controller

sudo apt-get install maas-rack-controller

sudo maas-rack register --url http://MAASサーバーアドレス:5240/

で治ることもあった.

参考ページ
Mac OSX上でISOイメージからBootable USBを作成する - 1日ひとつだけ強くなる
MAASの環境構築とUbuntuのデプロイ - Qiita
公開鍵暗号を用いてのSSH接続(きほん) - Qiita

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

DjangoでTodoアプリを作る⑤タスク編集機能の作成

次にタスク編集機能を作成していきます。

記事一覧

DjangoでTodoアプリを作る①Dockerで環境を構築する
DjangoでTodoアプリを作る②フォルダ一覧ページの作成
DjangoでTodoアプリを作る③タスク一覧ページの作成
DjangoでTodoアプリを作る④フォルダー、タスク作成機能の実装
DjangoでTodoアプリを作る⑤タスク編集機能の作成

URLの設定

まず、URLを設定していきます。
todo/urls.pyに次の一文を加えてください。

todo/urls.py
path('<int:id>/tasks/<int:task_id>', views.edit_task, name='tasks.edit')

リンクの挿入

templates/index.html編集の部分に以下のようにリンクを挿入します。

templates/index.html
<a href="{% url 'tasks.edit' id=current_folder_id task_id=task.id %}}">編集</a>

テンプレート

templatesディレクトリ下にedit.htmlを作成します。
そして、edit.htmlを以下のように編集します。

templates/edit.html
{% extends 'base.html' %}

{% block styles %}
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
  <link rel="stylesheet" href="https://npmcdn.com/flatpickr/dist/themes/material_blue.css">
{% endblock %}

{% block content %}
  <div class="container">
    <div class="row">
      <div class="col col-md-offset-3 col-md-6">
        <nav class="panel panel-default">
          <div class="panel-heading">タスクを編集する</div>
          <div class="panel-body">
            <form method="POST">
              {% csrf_token %}
              {{ form.as_p }}
              <div class="text-right">
                <button type="submit" class="btn btn-primary">送信</button>
              </div>
            </form>
          </div>
        </nav>
      </div>
    </div>
  </div>
{% endblock %}

{% block scripts %}
  <script src="https://npmcdn.com/flatpickr/dist/flatpickr.min.js"></script>
  <script src="https://npmcdn.com/flatpickr/dist/l10n/ja.js"></script>
  <script>
    flatpickr(document.getElementsByName('due_date'), {
      locale: 'ja',
      minDate: new Date()
    });
  </script>
{% endblock %}

次に、viewを書いていきます。

View

viewに以下のedit_taskメソッドを追加します。

views.py
def edit_task(request, id, task_id):
    #選ばれたタスクを取得する
    task = get_object_or_404(Task, id=task_id)
    if request.method == "POST":
        form = TaskForm(request.POST, instance=task)
        if form.is_valid():
            task = form.save(commit=False)
            task.save()
            return redirect('tasks.index', id=task.folder_id.id)
    else:
        form = TaskForm(instance=task)
    return render(request, 'edit.html', {'form': form}, {'task':task})

request.POST にデータが追加されているとき、formに入力された内容がデータベースに保存されるようにif文の処理を書いています。

完成!

これでこのチャプターは終わりで、Todoアプリの完成です!
ここまでのコードは、リポジトリのchapter5ブランチにあります。

ここからさらに、削除機能とか認証機能とかつけることもできると思うので、カスタマイズしながらやってみるのもいいと思います!
このチュートリアルを参考にしていただきありがとうございました!

記事一覧

DjangoでTodoアプリを作る①Dockerで環境を構築する
DjangoでTodoアプリを作る②フォルダ一覧ページの作成
DjangoでTodoアプリを作る③タスク一覧ページの作成
DjangoでTodoアプリを作る④フォルダー、タスク作成機能の実装
DjangoでTodoアプリを作る⑤タスク編集機能の作成

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

DjangoでTodoアプリを作る④フォルダー、タスク作成機能の実装

次は、フォルダー、タスク作成機能を実装していきます。

記事一覧

DjangoでTodoアプリを作る①Dockerで環境を構築する
DjangoでTodoアプリを作る②フォルダ一覧ページの作成
DjangoでTodoアプリを作る③タスク一覧ページの作成
DjangoでTodoアプリを作る④フォルダー、タスク作成機能の実装
DjangoでTodoアプリを作る⑤タスク編集機能の作成

フォルダー作成機能の実装

URLの設定

まず、以下の定義を踏まえてURLを設定していきます。

URL 処理
/folders/create フォルダーを新たに作成する

この設計にするために、todo/urls.pyに次の一文を加えてください。

todo/urls.py
path('create', views.create_folder, name='folders.create')

フォームの作成

まず、todoディレクトリの下にforms.pyというファイルを作成してください。
このファイルは、フォームを作成するのに必要なファイルです。

forms.pyを以下のように編集します。

forms.py
from django import forms
from .models import Folder

class FolderForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(FolderForm, self).__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs = {
                'class': 'form-control'
            }
    class Meta:
        model = Folder
        fields = ('title',)
        labels = {'title' : 'フォルダー名'}

formを作成するために必要なformsFolderモデルを1,2行目でインポートしています。
__init__の部分で、FolderFormのクラス名をform-controlにしています。これは、bootstrapを適用させるためです。

djangoには、django.forms.ModelForm と言う Modelクラスを元にFieldを自動的に生成してくれるクラスがあります。登録や更新処理ではModelFormクラスを使うのが便利なようです。

Metaクラスの変数の意味は以下の通りです。

変数名 意味
model 紐付けるModelクラスを指定する
fields Modelから入力フォームを生成する対象のフィールドをタプル形式で指定する
labels 入力欄の表示名を変更する。(例えば、今回指定していなければ、表示名が「title」になる)

フォルダー作成ページへのリンク

templates/index.htmlフォルダーを追加するの部分にリンクを以下のように追加します。

index.html
<a href="{% url 'folders.create' %}" class="btn btn-default btn-block">

テンプレート

templatesディレクトリ下にcreate_folders.htmlを作成します。
create_folders.htmlを以下のように編集します。

templates/create_folders.html
{% load static %}
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Todo</title>
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootflat/2.0.4/css/bootflat.min.css">
  <link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
  <header>
    <nav class="my-navbar">
      <a class="my-navbar-brand" href="/">Todo</a>
    </nav>
  </header>
  <main>
    <div class="container">
        <div class="row">
          <div class="col col-md-offset-3 col-md-6">
            <nav class="panel panel-default">
              <div class="panel-heading">フォルダーを追加する</div>
              <div class="panel-body">
                <form method="POST">
                  {% csrf_token %}
                  {{ form.as_p }}
                  <div class="text-right">
                      <button type="submit" class="btn btn-primary">送信</button>
                  </div>
                </form>
              </div>
            </nav>
          </div>
        </div>
      </div>
  </main>
</body>
</html>

以下の部分でCSRF対策を行っています。

templates/create_folders.html
{% csrf_token %}

また、以下の部分でフォルダー作成のためのフォームを展開しています。

create_folders.html
{{ form.as_p }}

as_pとは、

<p>
formの内容
</p>

という形で展開されるということです。

次に、viewを書いていきます。

View

viewに以下のcreate_folderメソッドを追加します。

views.py
from django.shortcuts import render, get_object_or_404, redirect#redirect関数を追加
from .forms import FolderForm


def create_folder(request):
    if request.method == "POST":
        form = FolderForm(request.POST)
        if form.is_valid():
            folder = form.save(commit=False)
            folder.created_at = timezone.now()
            folder.save()
            return redirect('tasks.index', id=folder.id)
    else:
        form = FolderForm()
    return render(request, 'create_folders.html', {'form': form})

まず最初に、作成したFolderFormとredirect関数をインポートしています。

その後に、create_folder関数を定義しています。
request.POST にデータが追加されているとき、formに入力された内容がデータベースに保存されるようにif文の処理を書いています。

確認

これでフォルダー作成機能は実装できました!
http://localhost:8000/folders/create にしてみて、以下のように表示されていればOKです!
フォルダー作成機能.png

タスク作成機能の実装

URLの設定

まず、以下の定義を踏まえてURLを設定していきます。

URL 処理
<int:id>/tasks/create タスクを新たに作成する

この設計にするために、todo/urls.pyに次の一文を加えてください。

todo/urls.py
path('<int:id>/tasks/create', views.create_task, name='tasks.create')

フォームの作成

forms.pyでタスク作成のためのフォームを作成します。
以下の、TaskFormクラスを追加します

todo/forms.py
from .models import Folder, Task#Taskモデルをインポート

class TaskForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(TaskForm, self).__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs = {
                'class': 'form-control'
            }
    class Meta:
        STATUS_CHOICES = [(1, '未完了'),(2, '作業中'),(3, '完了')]
        model = Task
        fields = ('title', 'status','due_date')
        labels = {
            'title': 'タスク名',
            'status': '状態',
            'due_date': '期限',
        }

まずはじめに、Taskモデルをインポートしています。
そしてTaskFormクラスを追加しています。

フォルダー作成ページへのリンク

templates/index.htmlタスクを追加するの部分にリンクを以下のように追加します。

index.html
<a href="{% url 'tasks.create' id=current_folder
_id %}" class="btn btn-default btn-block">

テンプレート

templatesディレクトリ下にcreate_tasks.htmlを作成します。
create_tasks.htmlを以下のように編集します。

templates/create_tasks.html
{% load static %}
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Todo</title>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
  <link rel="stylesheet" href="https://npmcdn.com/flatpickr/dist/themes/material_blue.css">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootflat/2.0.4/css/bootflat.min.css">
  <link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
<header>
  <nav class="my-navbar">
    <a class="my-navbar-brand" href="/">Todo</a>
  </nav>
</header>
<main>
    <div class="container">
        <div class="row">
          <div class="col col-md-offset-3 col-md-6">
            <nav class="panel panel-default">
              <div class="panel-heading">タスクを追加する</div>
              <div class="panel-body">
                <form method="POST">
                  {% csrf_token %}
                  {{ form.as_p }}
                  <div class="text-right">
                    <button type="submit" class="btn btn-primary">送信</button>
                  </div>
                </form>
              </div>
            </nav>
          </div>
        </div>
      </div>
</main>

<script src="https://npmcdn.com/flatpickr/dist/flatpickr.min.js"></script>
<script src="https://npmcdn.com/flatpickr/dist/l10n/ja.js"></script>
<script>
  flatpickr(document.getElementsByName('due_date'), {
    locale: 'ja',
    minDate: new Date()
  });
</script>
</body>
</html>

次に、viewを書いていきます。

View

viewに以下のcreate_taskメソッドを追加します。

views.py
from .forms import FolderForm, TaskForm#TaskFormをインポートする

def create_task(request, id):
    #選ばれたフォルダを取得する
    current_folder = get_object_or_404(Folder, id=id)
    if request.method == "POST":
        form = TaskForm(request.POST)
        if form.is_valid():
            task = form.save(commit=False)
            task.created_at = timezone.now()
            task.folder_id = current_folder
            task.save()
            return redirect('tasks.index', id=current_folder.id)
    else:
        form = TaskForm()
    return render(request, 'create_tasks.html', {'form': form}, {'id':current_folder.id})

注意するところは以下の部分。

task.folder_id = current_folder

folder_idは外部キーですが、外部キーを設定するときはオブジェクトを渡す必要があります(今回の場合はFolderオブジェクト)。

テンプレートの拡張

テンプレートは同じ情報やレイアウトを複数の場所で利用したいときに役立ちます。 各ファイル内で繰り返す必要はありません。

元となるテンプレートを作るために、todo/templatesディレクトリ配下にbase.htmlファイルを作ります。

templates
├── base.html
├── create_folders.html
├── create_tasks.html
└── index.html

base.htmlを以下のように編集します。

base.html
{% load static %}
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Todo</title>
  {% block styles %}
  {% endblock %}
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootflat/2.0.4/css/bootflat.min.css">
  <link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
<header>
  <nav class="my-navbar">
    <a class="my-navbar-brand" href="{% url 'tasks.index' id=1 %}">Todo</a>
  </nav>
</header>
<main>
    {% block content %}
    {% endblock %}
</main>
{% block scripts %}
{% endblock %}
</body>
</html>

以下の部分、HTMLが挿入されていきます。

  {% block styles %}
  {% endblock %}

ファイルの最初に以下を記述することで、base.htmlを拡張していくことができます。

{% extends 'base.html' %}

これをもとに、create_folders.htmlcreate_tasksindex.htmlを以下のように編集します。

create_folders.html
{% extends 'base.html' %}

{% block content %}
  <div class="container">
    <div class="row">
      <div class="col col-md-offset-3 col-md-6">
        <nav class="panel panel-default">
          <div class="panel-heading">フォルダーを追加する</div>
          <div class="panel-body">
            <form method="POST">
              {% csrf_token %}
              {{ form.as_p }}
              <div class="text-right">
                  <button type="submit" class="btn btn-primary">送信</button>
              </div>
            </form>
          </div>
        </nav>
      </div>
    </div>
  </div>
{% endblock %}
create_tasks.html
{% extends 'base.html' %}

{% block styles %}
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
  <link rel="stylesheet" href="https://npmcdn.com/flatpickr/dist/themes/material_blue.css">
{% endblock %}

{% block content %}
  <div class="container">
    <div class="row">
      <div class="col col-md-offset-3 col-md-6">
        <nav class="panel panel-default">
          <div class="panel-heading">タスクを追加する</div>
          <div class="panel-body">
            <form method="POST">
              {% csrf_token %}
              {{ form.as_p }}
              <div class="text-right">
                <button type="submit" class="btn btn-primary">送信</button>
              </div>
            </form>
          </div>
        </nav>
      </div>
    </div>
  <div>
{% endblock %}

{% block scripts %}
  <script src="https://npmcdn.com/flatpickr/dist/flatpickr.min.js"></script>
  <script src="https://npmcdn.com/flatpickr/dist/l10n/ja.js"></script>
  <script>
    flatpickr(document.getElementsByName('due_date'), {
      locale: 'ja',
      minDate: new Date()
    });
  </script>
{% endblock %}


index.html
{% extends 'base.html' %}

{% block content %}
  <div class="container">
    <div class="row">
      <div class="col col-md-4">
        <nav class="panel panel-default">
          <div class="panel-heading">フォルダー</div>
          <div class="list-group">
            {% for folder in folders %}
            <a 
            href="{% url 'tasks.index' id=folder.id %}",
            class="list-group-item {% if current_folder_id == folder.id %}active{% endif %}"
           >
              {{ folder.title }}
            </a>
            {% endfor %}
          </div>
          <div class="panel-body">
            <a href="{% url 'folders.create' %}" class="btn btn-default btn-block">
              フォルダーを追加する
            </a>
          </div>
        </nav>
      </div>
      <div class="column col-md-8">
        <div class="panel panel-default">
          <div class="panel-heading">タスク</div>
          <table class="table">
            <thead>
            <tr>
              <th>タイトル</th>
              <th>状態</th>
              <th>期限</th>
              <th></th>
            </tr>
            </thead>
            <tbody>
              {% for task in tasks %}
                <tr>
                  <td>{{ task.title }}</td>
                  <td>
                    <span 
                    class="label {% if task.status == 1 %}label-danger{% endif %}{% if task.status == 2 %}label-info{% endif %}"
                    >
                    {{ task.get_status_display }}
                    </span>
                  </td>
                  <td>{{ task.due_date }}</td>
                  <td><a href="{% url 'tasks.edit' id=current_folder_id task_id=task.id %}">編集</a></td>
                </tr>
              {% endfor %}
            </tbody>
          </table>
          <div class="panel-body">
            <div class="text-right">
              <a href="{% url 'tasks.create' id=current_folder_id  %}" class="btn btn-default btn-block">
                タスクを追加する
              </a>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
{% endblock %}

おわりに

これでこのチャプターは終わりです!
ここまでのコードは、リポジトリのchapter4ブランチにあります。
次のチャプターではタスク編集機能を実装していきます!

記事一覧

DjangoでTodoアプリを作る①Dockerで環境を構築する
DjangoでTodoアプリを作る②フォルダ一覧ページの作成
DjangoでTodoアプリを作る③タスク一覧ページの作成
DjangoでTodoアプリを作る④フォルダー、タスク作成機能の実装
DjangoでTodoアプリを作る⑤タスク編集機能の作成

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

HTTP Real Worldの ハンズオンの準備をWindows10+Vagrant+Docker+VsCodeで行ったメモ

概要

Real World HTTP 第2版――歴史とコードに学ぶインターネットとウェブ技術を買った。
ハンズオンが準備されていたので、その環境設定を行ったメモ。

環境

  • Windows 10 Home
    • Vagrant 2.2.7
    • virtualbox 6.1.6
      • ubuntu 18.04 LTS
        • docker-ce Docker version 19.03.5, build 633a0ea838
        • docker-compose version 1.25.3, build d4d1b42b

環境構築

chocolateyの準備

  • 使用するパッケージを簡単にインストールできるように、Windows用のパッケージマネージャを導入
@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command " [System.Net.ServicePointManager]::SecurityProtocol = 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"

curl の準備

  • gitbashのものを使用する
choco install git -y

golangの準備

エディタ

  • vscodeのおススメを利用。(.vscode/extensions.json)に記述
  • 上記を利用するために、golangのパスの場所が必要になったのでchocolateyでインストール
choco install golang -y

実行環境

  • vagrant上でdockerを動かす。
docker/docker-compose.yml
version: "3"
services:
  realworld:
    build: ./golang
    volumes:
      - ../src:/app/src
    working_dir: /app
    ports:
      - 18888:18888
docker/golang/Dockerfile
FROM golang:latest
bin/go.sh
#!/bin/bash

bin_dir=$(cd $(dirname $0) && pwd)
parent_dir=$bin_dir/..
docker_dir=$parent_dir/docker
composeFile=${1:-"docker-compose.yml"}
container_name=${1:-realworld}

docker ps | grep $container_name

if [ $? -eq 0 ]; then
  cd $docker_dir && docker-compose exec $container_name go run /app/src/server.go
else
  cd $docker_dir && docker-compose run --service-ports $container_name go run /app/src/server.go
fi
src/server.go
package main

import (
    "fmt"
    "log"
    "net/http"
    "net/http/httputil"
)

func handler(w http.ResponseWriter, r *http.Request) {
    dump, err := httputil.DumpRequest(r, true)
    if err != nil {
        http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
        return
    }
    fmt.Println(string(dump))
    fmt.Fprintf(w, "<html><body>Hello</body></html>\n")
}

func main() {
    var httpServer http.Server
    http.HandleFunc("/", handler)
    log.Println("start http listening :18888")
    httpServer.Addr = ":18888"
    log.Println(httpServer.ListenAndServe())
}

動作確認

  • 上記を準備した後、vagrant上でgo.shを動かせば検証用のサーバが起動する。
    • curlでアクセスして確認 curl --http1.0 http://192.168.50.10:18888/greeting

参考

Chocolatey Software | Installation
Chocolateyを使った環境構築の時のメモ
Docker で Go の開発環境を構築する
VSCode + golang での快適な補完について自分なりにまとめてみた
docker-compose run は port を mapping しない

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

コンテナオーケストレーション入門?#1(Swarmを使ってみる)

はじめに

Swarmを使用しながら、コンテナオーケストレーションの概要を体験したいと思います。

環境

  • macOS Mojave 10.14.6
  • Docker engine 19.03.5

内容

  • Swarm機能を有効化する
  • サービスを作成する
  • タスクを確認する
  • レプリカを作成する
  • コンテナをダウンさせ、復旧させる

Swarm機能をOnにする

SwarmはDockerに付属しているAPIではあるものの、デフォルトでは使用できない状態になっています。
使用するためには、設定を変更する必要があります。

現在の設定を確認する

以下のコマンドを使用することで、現在のDockerの設定を確認することができます。

docker info
...
#  Swarm: inactive (Swarmが使用できない状態)

Swarm機能をOnにする

以下のコマンドを使用することで、Swarm機能を有効化します。

docker swarm init

# Swarm initialized: current node (lo0dewyehl9qi1fd1thnza9bx) is now a manager.

# To add a worker to this swarm, run the following command:

#     docker swarm join --token SWMTKN-1-3y9vcbhfi1ppllmqj1971ua0brhx7k52gjmhlu0264oxjpsrqm-7rbc4fnt7llsze1ou22uszkbh 192.168.65.3:2377

# To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

このノードは新しいマネジャーです。

と表示されています。
どういうことでしょうか。

docker swarm initで起こること

docker swarm initを行うと、今後Swarmを使用していくに当たって必要な設定が自動で行われます。
例えば...

  • 公開鍵基盤(PKI)の自動設定
  • ルート証明書の設定
  • Join Tokenの生成

Swarmを使用することで、コンテナやそのネットワークはどんどん拡張されていきます。
ネットワークの通信を暗号化したりなど、ネットワークセキュリティに必要な内容を自動で設定しています。

また、RAFTデータベースがバックグラウンドで作成されています。
ここにはSwarmの構成や最初のマネジャーが格納され、暗号化されています。

このDBが自動で生成されているおかげで、これまで必要とされてきたコンフィグ用のDBは必要ありません。

docker node ls

以下のコマンドを使用することで、ノードの一覧を確認することができます。

docker node ls
ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
lo0dewyehl9qi1fd1thnza9bx *   docker-desktop      Ready               Active              Leader              19.03.8

docker swarm initを実行したことで、マネジャーノードが1つ作成されています。
また、StatusがLeaderとなっています。

Pets vs Cattles

オンプレミスとクラウドは、しばしばペットと家畜に例えられます。
これはコンテナオーケストレーションを扱う際にも当てはまります。

クラウド以前は、サーバー1台をオンプレミスで運用し、不調があれば修正するなどペットのように可愛がる必要がありました。

クラウドの時代では、サーバー1台だけを運用する事はありません。複数台のサーバー群を運用し、不調の際は手間をかける事なく落とし、代わりを立ち上げます。

コンテナオーケストレーションは、まさにコンテナやノードを「群れ」という単位で扱います。
群れに対して操作を行い、新しい群れを作成したり、群ごと削除したりできます。

docker service create

以下のコマンド実行することで、新しいサービスを作成することができます。
GoogleのDNSサーバー8.8.8.8にpingを送り続けるaplineイメージからサービスを作成します。

docker service create alpine ping 8.8.8.8
# zn0631k8t6067p9gb517m6p87

docker runした時と同じように、IDが出力されています。
これはサービスIDです。

docker service ls

以下のコマンドを実行することでサービスの一覧を確認することができます。

docker service ls
# ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
# zn0631k8t606        kind_perlman        replicated          1/1                 alpine:latest       

'REPLICAS'の値を確認することで、サービスの実行数が確認できます。
今は1/1となっています。

docker service ps

以下のコマンドを使用することで、サービス内に含まれるタスク(コンテナ)の一覧を表示することができます。

docker service ps kind_perlman
# ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
# taaj0dalmte5        kind_perlman.1      alpine:latest       docker-desktop      Running             Running 10 minutes ago                       

デフォルトで作成されたノードに、タスク(コンテナ)が作成されています。

docker service update

では、このサービスのレプリカを増やしてみます。
以下のupdateコマンドを実行することで、レプリカを増やし冗長化を図ることができます。

docker  service update zn06 --replicas 3
# zn06
# overall progress: 3 out of 3 tasks 
# 1/3: running   [==================================================>] 
# 2/3: running   [==================================================>] 
# 3/3: running   [==================================================>] 
# verify: Service converged 

docker service lsでサービスを確認すると、レプリカの数が増えていることが確認できます。

docker service ls
# ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
# zn0631k8t606        kind_perlman        replicated          3/3                 alpine:latest       

また、`docker service psを実行することで、コンテナも増えていることが確認できます。

docker service ps kind_perlman
# ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
# taaj0dalmte5        kind_perlman.1      alpine:latest       docker-desktop      Running             Running 18 minutes ago                       
# l5ply9585ptc        kind_perlman.2      alpine:latest       docker-desktop      Running             Running 2 minutes ago                        
# rhnb1bnfsic3        kind_perlman.3      alpine:latest       docker-desktop      Running             Running 2 minutes ago                        

コンテナのNAMEに、番号が自動で添えられているのもすごいですね。自動で名前が一意になるようになっています。

updateコマンドを使用することでコンテナを停止したり新しく作り直すことなしに、変更を加えることができます。
これは稼働率を確保する上で重要な特徴です。

これはSwarmを使用する目的の一つでもあります。コンテナやその集合でできた環境を停止することなく、レプリケーションしたり、変更を加えることができるようになります。

もしコンテナの一部がダウンしたら

もしコンテナの一部がダウンしたらどうなるか、試してみます。

以下のコマンドを使用して、コンテナの一つを削除してみます。

docker container rm -f  kind_perlman.1.taaj0dalmte5iqmagqgy97tbt

サービスを確認してみると、

docker service ls
# ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
# zn0631k8t606        kind_perlman        replicated          3/3                 alpine:latest       

あれ? 特に変化ありませんね。

では、タスク一覧を確認してみます。

docker service ps kind_perlman
# ID                  NAME                 IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR                         PORTS
# ztbj2mfbzqzh        kind_perlman.1       alpine:latest       docker-desktop      Running             Running 18 seconds ago                                 
# taaj0dalmte5         \_ kind_perlman.1   alpine:latest       docker-desktop      Shutdown            Failed 23 seconds ago    "task: non-zero exit (137)"   
# l5ply9585ptc        kind_perlman.2       alpine:latest       docker-desktop      Running             Running 37 minutes ago                                 
# rhnb1bnfsic3        kind_perlman.3       alpine:latest       docker-desktop      Running             Running 37 minutes ago                                 

コンテナkind_perlman.1は確かに削除されています。

でも、その数秒後には同名のコンテナが復活しています。

これがSwarmを初めとするコンテナオーケストレーションの強みです。
コンテナが落ちたとしても、即座に元の状態に自動て復旧します。

docker service rm

以下のコマンドを使用することで、サービスを削除することができます。

docker service rm 

サービスだけでなく、サービスに紐づいているタスク(コンテナ)も削除されます。

まとめ

  • Swarm機能を有効化する
  • サービスを作成する
  • タスクを確認する
  • レプリカを作成する
  • コンテナをダウンさせ、復旧させる

上記を確認しながら、コンテナオーケストレーションの強みがわかってきました。

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

初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)通信編 パート3

背景

個人的にインフラの知識以上にこれからのアプリケーションが動く環境を作ってデプロイしたりしてこれからの知識を身に着けたい。そしてより一層、自分の知識のアップデートをしたいと思いました。

その中でこの本に出会い、これから少しずつやったことを残し、未来の自分への手紙としてもあり、見つめ直せればと思いました。

引用や参考と今回の自分の勉強用の書籍の紹介

技術評論社『Kubernetes実践入門』のサンプルコード
Kubernetes実践入門 プロダクションレディなコンテナ&アプリケーションの作り方

実際の学びについて

書籍を読みながら、章ごとに少しずつ進めていきたいと思います。
GitHub のソースコードも使いながら学んで行きたいと思います。
この章の勉強は本当に書籍の写経が主になるかもしれません・・・

勉強開始

  • ExternalName を使って外部アプリケーションの名前を解決できることを確認します

書籍では -o wide を使用して確認しているので違いを比較できるように一旦確認

  • SELECTOR が表示されるかを確認します > 前の章でも Label が重要なことが説明されていました
-o wideなし
$ kubectl get svc,ep mattermost-db
NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/mattermost-db   ClusterIP   10.104.31.215   <none>        3306/TCP   16h

NAME                      ENDPOINTS         AGE
endpoints/mattermost-db   10.1.0.207:3306   16h
-o wide付き
$ kubectl get svc,ep mattermost-db -o wide
NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE   SELECTOR
service/mattermost-db   ClusterIP   10.104.31.215   <none>        3306/TCP   16h   run=db

NAME                      ENDPOINTS         AGE
endpoints/mattermost-db   10.1.0.207:3306   16h

Service を作成する

  • ClusterIP が作成されてないことを確認
  • Type が ExternalName になっていることを確認できます
$ kubectl create svc externalname ext-mattermost-db --external-name example.com
service/ext-mattermost-db created

$ kubectl get svc,ep ext-mattermost-db -o wide
NAME                        TYPE           CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE   SELECTOR
service/ext-mattermost-db   ExternalName   <none>       example.com   <none>    35s   app=ext-mattermost-db

NAME                          ENDPOINTS   AGE
endpoints/ext-mattermost-db   <none>      35s

作成した ext-mattermost-db / example.com の名前解決をしてみる

$ kubectl run -it --rm test3 --image=k8spracticalguide/busybox:1.28 --restart=Never -- /bin/sh
If you don't see a command prompt, try pressing enter.
/ # nslookup ext-mattermost-db
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      ext-mattermost-db
Address 1: 2606:2800:220:1:248:1893:25c8:1946
Address 2: 93.184.216.34 # ext-mattermost-dbを名前解決した結果

/ # nslookup example.com
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      example.com
Address 1: 2606:2800:220:1:248:1893:25c8:1946
Address 2: 93.184.216.34 # example.comを名前解決した結果

次は 3.5.4 章をやっていきます。

ClusterIP を使わない Headless Service を学んで行きます

最後に

個人的には、下記のようなコマンドで確認ができるよ!と書籍で記載してもらっているのが非常に助かりました。
何度も、コマンドラインで確認するために下記のようなコマンドが出現すると自然とこういう確認ができるよね!
って思える様になります

kubectl run -it --rm test3 --image=k8spracticalguide/busybox:1.28 --restart=Never -- /bin/sh

今回も、前回同様ポータビリティという言葉がぴったりハマりました。(ハマり はGood な意味です)
書籍の中で下記の言葉がすっごく印象的でした。引用させていただきます。

このように、クラスタ外部のアプリケーションであっても、ExternalName を使用することで内部のアプリケーションと同じように Service 名でアクセスできます。もし将来的に、本番環境のデータベースも Kubernetes クラスタ上にデプロイすることになったとしても、Service 名を変えずに Service の種類だけを変更できるので、データベースを使用するアプリケーションに変更が及びません。

今までの投稿

  1. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)Pod編
  2. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)NameSpace 編
  3. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)Label 編
  4. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)ReplicaSet 編
  5. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)Deployment 編
  6. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)Service 編
  7. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)ConfigMap 編
  8. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)Secret 編
  9. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)操作編
  10. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)体感編
  11. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)体感編パート2
  12. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)体感編パート3(Label操作)
  13. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)体感編パート3(OwnerReference 操作)
  14. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)マニュフェスト編
  15. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)マニュフェスト(ConfigMap)編
  16. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)通信編
  17. 初心者のKubernetes入門(書籍 Kubernetes 実践入門の写経から学ぶ)通信編 パート2
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UnityのPackageManagerに自分のパッケージを入れるまで

概要

最近、自作のEditor拡張等を入れてAssetフォルダに増えるのが厳しい感じがしたので、Unityの機能であるPackageManagerに登録することにしました。その備忘録になります。
PCに直接npmやらVerdaccio入れるのはつらい気持ちがあるので、Dockerなるものを使います。

材料

※私の環境はWindows10 Homeのため
* Docker Toolbox - v19.03.1

手順

1. 下準備

上記のDocker Toolboxはあらかじめインストールしておきます。
参考 - Windows環境にDocker Toolboxをインストールする

2. docker-compose.ymlを作る

docker composeってなんぞや?

Compose とは、複数のコンテナを使う Docker アプリケーションを、定義・実行するツールです。Compose はアプリケーションのサービスの設定に、Compose ファイルを使います。そして、コマンドを1つ実行するだけで、設定した全てのサービスを作成・起動します。 - Docker ドキュメント日本語化プロジェクトより

その複数のコンテナを使う Docker アプリケーションを、定義するためのファイルがdocker-compose.ymlとのことです。
まずは今回のプロジェクト用のフォルダを作成し、その中にdocker-compose.ymlファイルを配置します。
フォルダ構成はこんな感じ。(Cドライブのどこかに置くこと)

- LocalNpmPackageServer
  ├ verdaccio
  │ ├ config
  │ │ └ config.yml
  │ ├ plugins
  │ └ storage
  └ docker-compose.yml

中身は下記

docker-compose.yml
version: '3.1'

services:
  verdaccio:
    image: verdaccio/verdaccio
    container_name: "verdaccio"
    networks:
      - node-network
    environment:
      - VERDACCIO_PORT=4873
    ports:
      - "4873:4873"
    volumes:
      - "./verdaccio/storage:/verdaccio/storage"
      - "./verdaccio/config:/verdaccio/conf"
      - "./verdaccio/plugins:/verdaccio/plugins"  
networks:
  node-network:
    driver: bridge

今回はUnityのPackageManagerのレジストリサーバーとして、Verdaccioの構成を定義しています。

3. config.yamlを作る

Verdaccioのコンフィグファイルを作成します。docker-compose.ymlのvolumesに定義されている ./verdaccio/configに配置します。
中身は下記。

config.yml
storage: ../storage
auth:
  htpasswd:
    file: ./htpasswd
uplinks:
  npmjs:
    url: https://registry.npmjs.org/
packages:
  '**':
    access: $all
    publish: $authenticated
    proxy: npmjs
logs:
  - {type: stdout, format: pretty, level: http}

ここで定義されているstoregeの位置はdocker-compose.ymlのvolumesに定義した./verdaccio/storageの位置です。

4.起動する

Docker Toolboxを入れたタイミングでDocker Quickstart Terminalが追加されているはずなので、起動します。
くじらのAAの黒い画面が出てきたら、docker is configured to use the default machine with IP なんとかと、IPアドレスが出ているので覚えておきましょう。
そしてdocker-compose.ymlを置いたプロジェクトフォルダへ移動します。

コマンド
cd "プロジェクトフォルダのパス"

移動したらDockerを起動するためのコマンドを入れます。

コマンド
# デーモン状態で起動する場合はこっち(このターミナルを閉じても動いてる)
docker-compose up -d

# 普通に動かす場合はこっち
docker-compose up

http://先ほど出ていたIPアドレス:4873をブラウザに入れて、Verdaccioの画面が表示されたらこれで環境は作成完了です。

5. パッケージを作成する

参考 - UNITYPACKAGEMANAGERのレジストリサーバーを立てる話

Unityでの作業になります。

  • パッケージ構成について

個人的にはこのようなフォルダ構成にしています。

- OriginalPackage
  │ ├ Runtime
  │ │ └ OriginalPackage.Runtime.asmdef
  │ ├ Editor
  │ │ └ OriginalPackage.Editor.asmdef
  └ package.json

この時に注意するのはEditorのAssembly DefinitionのPlatformsの設定で、Any Platformのチェックを外し、Editorのみにしておきます。
また、後ほどPackageManagerからインストールする際に既に存在しているとインストールできないため、同じプロジェクトに入れる場合は最初の作成が終わったら登録する前に別の(プロジェクト外の)場所に移しておきましょう。

  • package.jsonについて

中身は下記

package.json
{
  "name": "jp.co.mypackage.originalpackage",
  "displayName": "Original Package",
  "version": "1.0.0",
  "unity": "2018.1",
  "description": "My original package.",
  "keywords": [
    "editor"
  ],
  "category": "",
  "relatedPackages": {},
  "dependencies": {},
  "repository": {},
  "author": {
    "name": "My Name",
    "url": ""
  },
  "license": {
    "type": "MIT",
    "url": "https://monry.mit-license.org"
  }
}

このうち、上から5項目(name・displayName・version・unity・description)は必須です。
上記の必須でない項目の一部はVerdaccioで表示されたりします。

6.パッケージを登録する

またDocker Quickstart Terminalに戻ります。

まずユーザー登録をします。

コマンド
npm adduser --registry  http://4で出てたIP:4873

ユーザー名、パスワード、メアドを登録します。
で、ログイン。

コマンド
npm login --registry  http://4で出てたIP:4873

で、登録。

コマンド
cd "OriginalPackageのフォルダパス"
npm publish --registry  http://4で出てた:4873

これで登録完了です。
ちなみに上記のコマンドたちは、立ち上げたVerdaccioのページに書いてあるのでコピペすると良いです。

この状態でVerdaccioのページを読み込み直すとパッケージが登録されているのが確認できると思います。

7.UnityのPackageManagerからインストールする

最後です。Unityのプロジェクトフォルダ/Package/manifest.jsonを開きます。
そこに下記のようにscopedRegistriesを追加します。(dependencies以下は元からあるはずです)

manifest.json
{
  "scopedRegistries": [
    {
      "name": "my-package-name",
      "url": "http://4で出てたIP:4873/",
      "scopes": [
        "jp.co.mypackage"
      ]
    }
  ],
  "dependencies": {
    "com.unity.collab-proxy": "1.2.16",
    "com.unity.ide.rider": "1.1.4",
    "com.unity.ide.vscode": "1.1.4",
    "com.unity.test-framework": "1.1.11",
    "com.unity.textmeshpro": "2.0.1",
    "com.unity.timeline": "1.2.12"
  }
}

これでUnityに戻りPackageManagerを見ると出ていると思います。

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

【LINUXコマンド】オプションの短縮表記一覧

オプションの短縮表記一覧

______________________
コマンド
A____
-a
-A
B____
-b
-B
C____
-c
-C
D____
-d
-D
E____
-e
-E
F____
-f
-F
G____
-g
-G
H____
-h
-H
I____
-i
-I
J____
-j
-J
K____
-k
-K
L____
-l
-L
M____
-m
-M
N____
-n
-N
O____
-o
-O
P____
-p
-P
Q____
-q
-Q
R____
-r
-R
S____
-s
-S
T____
-t
-T
U____
-u
-U
V____
-v
-V
W____
-w
-W
X____
-x
-X
Y____
-y
-Y
Z____
-z
-Z
0____
-0
1____
-1
2____
-2
3____
-3
4____
-4
5____
-5
6____
-6
7____
-7
8____
-8
9____
-9
#____
-#
_____
-?
ls1 a2
A3
b4
B5
c6
C7
d8
D9
- f10
F11
G12 h13
H14
i15
I16
- k17 l18
L19
m20 n21
N22
o23 p24 q25
Q26
R27 s28
S29
t30
T31
u32
U33
v34 w35 x36
X37
- Z38 - 139 - - - - - - - - - -
touch40 a41 - c42 d43 - f44 - h45 - - - - m46 - - - - r47 - t48 - - - - - - - - - - - - - - - - - -
cp49 a50 b51 c52 d53 - f54 - H55 i56 - - l57 - n58 - p59
P60
q r27
R27
s61 t62
T63
u64 v65 - x66 - Z67 - - - - - - - - - - - -
mv68 - b69 - - - f54 - - i56 - - - - n58 - - - - S70 t62
T63
u64 v65 - - - Z38 - - - - - - - - - - - -
mkdir71 - - - - - - - - - - - - m72 - - p73 - - - - - v65 - - - Z74 - - - - - - - - - - - -
rmdir75 - - - - - - - - - - - - - - - p73 - - - - - v65 - - - - - - - - - - - - - - - -
chown76 - - c77 - - f78 - h45
H79
- - - L80 - - - P81 - R27 - - - v65 - - - - - - - - - - - - - - - -
chmod82 - - c77 - - f78 - - - - - - - - - - - R27 - - - v65 - - - - - - - - - - - - - - - -
cat83 A84 b85 - - e86
E87
- - - - - - - - n88 - - - - s89 t90
T91
u92 v93 - - - - - - - - - - - - - - - -
head94 - - c95 - - - - - - - - - - n96 - - q97 - - - - v65 - - - - - - - - - - - - - - - -
tail98 - - c95 - - f99
F100
- - - - - - - n96 - - q97 - s101 - - v65 - - - - - - - - - - - - - - - -
wc102 - - c95 - - - - - - - - l103
L104
m105 - - - - - - - - - w106 - - - - - - - - - - - - - - -
sort107 - b108 c109
C110
d111 - f112 g113 h114 i115 - k116 - m117
M118
n119 o120 - - r121
R122
s123
S124
t125
T126
u127 V128 - - - z129 - - - - - - - - - - - -
uniq130 - - c131 d132
D133
- f134 - - i135 - - - - - - - - - s136 - u127 - w137 - - z129 - - - - - - - - - - - -
diff138 a139 b140
B141
c142
C142
d143
D144
e145
E146
F147 - - i135
I148
- - l149 - n150
N151
- p152 q153 r27 s154
S155
t156
T157
u158
U158
v159 w160
W35
x161
X162
y163 Z164 - - - - - - - - - - - -
grep165 a139
A166
b167
B168
c131
C142
d169
D170
e171
E172
f173
F174
G175 h176
H177
i135
I178
- - l179
L180
m181 n182 o183 P184 q97 r27
R185
s186 T157 u187
U188
v189
V159
w190 x191 - z192
Z193
- - - - - - - - - - - -
curl194 a195
A196
b197
B198
c199
C200
d201
D202
e203
E204
f205
F206
g207
G208
h209
H210
i211
I212
j213
J214
k215
K216
l217
L218
m219
M220
n221
N222
o120
O223
p224
P225
q226
Q227
r228
R229
s230
S231
t232
T233
u234
U235
v65
V159
w236 x237
X238
y239
Y240
z241 0242 1243 2244 3245 4246 - 6247 - - - #248 -
tar249 a250
A251
b252
B253
c254
C255
d256 - f173
F257
g258
G259
h260
H261
i262
I263
j264
J265
k266
K267
l268
L269
m270
M271
n272
N273
o274
O275
p276
P277
- r278
R279
s280
S281
t282
T283
u64
U284
v65
V285
w286
W287
x288
X162
- z289
Z290
- - - - - - - - - - - ?291
gzip292 - - c293 d294 - f54 - h209 - - - l295
L296
- n297
N298
- - q299 r27 S70 t300 - v65
V159
- - - - - 1301 - - - - - - - 9302 - -
kill303 a2 - - - - - - h209 - - - l295
L304
- - - p305 q306 - s307 - - V159 - - - - - - - - - - - - - - - -
df308 a2 B309 - - - - - h13
H310
i311 - k312 l313 - - - P314 - - - t315
T316
- v317 - x318 - - - - - - - - - - - - - -
free319 - b320 c131 - - - g321 h322 - - k323 l324 m325 - - - - - s326 t327 - V159 w328 - - - - - - - - - - - - - - -
vmstat329 a330 - - d331
D332
- f333 - h209 - - - - m334 n335 - p336 - - s337
S338
t339 - V159 w328 - - - - - - - - - - - - - - -
git clone340 - b341 c342 - - - - - - j343 - l313 - n344 o345 - q299 - s346 - u347 v65 - - - - - - - - 4246 - 6247 - - - - -
git init348 - - - - - - - - - - - - - - - - q299 - - - - - - - - - - - - - - - - - - - - -
git add349 A2 - - - e350 f54 - - i56 - - - - n351
N352
- p353 - - - - u64 v65 - - - - - - - - - - - - - - - -
git mv354 - - - - - f54 - - - - k355 - - n351 - - - - - - - v65 - - - - - - - - - - - - - - - -
git restore356 - - - - - - - - - - - - m117 - - p353 q299 - s357
S358
- - - W359 - - - - - 2360 3361 - - - - - - - -
git rm362 - - - - - f54 - - - - - - - n351 - - q299 r363 - - - - - - - - - - - - - - - - - - - -
git diff364 a139 b140
B365
C366 D367 - - G368 - - - - l369 M370 - O371 p353 - R372 s373
S374
- u375
U158
- w160
W376
X377 - z378 - - - - - - - - - - - -
git grep379 a139
A166
B168 c131
C142
- e380
E172
f381
F174
G175 h382
H383
i135
I384
- - l180
L180
- n182 o183
O385
p386
P184
q299 r27 - - - v189 w190
W376
- - z193 - - - - - - - - - - - -
git log387 - - - - - - - - - - - L388 - - - - q299 - - - - - - - - - - - - - - - - - - - - -
git show389 - - - - - - - - - - - L390 - - - - q299 - - - - - - - - - - - - - - - - - - - - -
git status391 - b341 - - - - - - - - - - M370 - - - - - s392 - u393 v65 - - - z193 - - - - - - - - - - - -
git branch394 a2 - c395C396 d397
D398
- f54 - - i135 - - l295 m399
M400
- - - q299 r401 - t402 u403 v65 - - - - - - - - - - - - - - - -
git commit404 a2 - c405
C406
- e350 F173 - - i211 - - - m407 n408 o409 p353 q299 - s410
S411
t412 u393 v65 - - - z193 - - - - - - - - - - - -
git merge413 - - - - e350 F173 - - - - - - m407 n414 - - q299 - s415
S411
- - v65 - X416 - - - - - - - - - - - - - -
git rebase417 - - C418 - - f419 - - i56 - k420 - m117 n421 - - q299 r422 s415
S411
- - v65 - x423
X416
- - - - - - - - - - - - - -
git reset424 - - - - - - - - - - - - - n352 - p353 q299 - - - - - - - - - - - - - - - - - - - - -
git switch425 - - c254
C426
d427 - f54 - - - - - - m117 - - - q299 - - t402 - - - - - - - - - - - - - - - - - -
git tag428 a429 - - d397 e350 f54
F173
- - i135 - - l295 m407 n430 - - - - s431 - u432 v433 - - - - - - - - - - - - - - - -
git fetch434 a195 - - - - f54 - - - j343 k435 - m436 n437 o438 p439
P440
q299 - - t441 u442 v65 - - - - - - - - 4246 - 6247 - - - - -
git pull443 a195 - - - - f54 - - - j343 k435 - - n444 - p439 q299 r445 s415
S411
t441 - v65 - X416 - - - - - - 4246 - 6247 - - - - -
git push446 - - - - d397 f54 - - - - - - - n351 o447 - q299 - - - u448 v65 - - - - - - - - 4246 - 6247 - - - - -
docker build449 - - c450 - - f173 - - - - - - m451 - - - q299 - - t452 - - - - - - - - - - - - - - - - - -
docker commit453 a454 - c455 - - - - - - - - - m407 - - p456 - - - - - - - - - - - - - - - - - - - - - -
docker cp457 a50 - - - - - - - - - - L458 - - - - - - - - - - - - - - - - - - - - - - - - - -
docker create459 a460 - c450 - e461 - - h462 i56 - - l463 m451 - - p464
P465
- - - t466 u234 v467 w468 - - - - - - - - - - - - - - -
docker events469 - - - - - f470 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
docker exec471 - - - d427 e461 - - - i56 - - - - - - - - - - t466 u234 - w468 - - - - - - - - - - - - - - -
docker export472 - - - - - - - - - - - - - - o120 - - - - - - - - - - - - - - - - - - - - - - -
docker history473 - - - - - - - h322 - - - - - - - - q299 - - - - - - - - - - - - - - - - - - - - -
docker images474 a2 - - - - f470 - - - - - - - - - - q299 - - - - - - - - - - - - - - - - - - - - -
docker import475 - - c455 - - - - - - - - - m407 - - - - - - - - - - - - - - - - - - - - - - - - -
docker info476 a2 - - - - f477 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
docker inspect478 - - - - - f477 - - - - - - - - - - - - s28 - - - - - - - - - - - - - - - - - - -
docker kill479 - - - - - - - - - - - - - - - - - - s307 - - - - - - - - - - - - - - - - - - -
docker load480 - - - - - - - - i481 - - - - - - - q299 - - - - - - - - - - - - - - - - - - - - -
docker login482 - - - - - - - - - - - - - - - p483 - - - - u234 - - - - - - - - - - - - - - - - -
docker logs484 - - - - - f99 - - - - - - - - - - - - - t485 - - - - - - - - - - - - - - - - - -
docker ps486 a2 - - - - f470 - - - - - l487 - n488 - - q299 - s28 - - - - - - - - - - - - - - - - - - -
docker pull489 a2 - - - - - - - - - - - - - - - q299 - - - - - - - - - - - - - - - - - - - - -
docker restart490 - - - - - f99 - - - - - - - - - - - - - t491 - - - - - - - - - - - - - - - - - -
docker rm492 - - - - - f54 - - - - - l57 - - - - - - - - - v493 - - - - - - - - - - - - - - - -
docker rmi494 - - - - - f54 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
docker run495 a460 - c450 d427 e461 - - h462 i56 - - l463 m451 - - p464
P465
- - - t466 u234 v467 w468 - - - - - - - - - - - - - - -
docker save496 - - - - - - - - - - - - - - o120 - - - - - - - - - - - - - - - - - - - - - - -
docker search497 - - - - - f470 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
docker start498 a460 - - - - - - - i56 - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
docker stats499 a2 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
docker stop500 - - - - - - - - - - - - - - - - - - - t491 - - - - - - - - - - - - - - - - - -
docker update501 - - c450 - - - - - - - - - m451 - - - - - - - - - - - - - - - - - - - - - - - - -
docker version502 - - - - - f477 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

青字: エイリアスオプションなし
赤字: エイリアスオプションがあるが、頭文字が異なる

感想

lstarcurl など、短縮表記を丸暗記しまっているものを、横並びに確認することで、理解が深まるかと思い作成した。(ただし、めちゃくちゃ時間がかかった。)
短縮表記は、よく使われるオプションでもあるので、コマンドの理解も少し深まった。
類似が多いわけではないので、あまり役に立たないかもしれないが、自分でオプション付きのコマンドを作るときは参考になるかもしれない。
ただし、自分でコマンドを作るとき、短縮表記は必要最低限から始めるのがいいだろう。

編集リクエストも歓迎しています。
※ ただし、注釈が多すぎるためか、投稿/更新に失敗する頻度がとても高いので注意

その他(編集用テキスト)

|command[^command]|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z|0|1|2|3|4|5|6|7|8|9|#|?|

  1. ls (GNU coreutils) 8.22 ls --help 参照 

  2. --all 

  3. --almost-all 

  4. --escape 

  5. --ignore-backups 

  6. with -lt: sort by, and show, ctime (time of last modification of file status information); with -l: show ctime and sort by name; otherwise: sort by ctime, newest first 

  7. list entries by columns 

  8. --directory 

  9. --dired 

  10. do not sort, enable -aU, disable -ls --color 

  11. --classify 

  12. --no-group 

  13. --human-readable 

  14. --dereference-command-line 

  15. --inode 

  16. --ignore 

  17. --kibibytes 

  18. 詳細リスト形式を表示する 

  19. --dereference 

  20. 要素のリストをカンマで区切り、一行に詰め込む 

  21. --numeric-uid-gid 

  22. --literal 

  23. -l と同様だがグループ情報を表示しない 

  24. --indicator-style 

  25. --hide-control-chars 

  26. --quote-name 

  27. --recursive 

  28. --size 

  29. sort by file size 

  30. ファイル更新時間で新しい順にソートする 

  31. --tabsize 

  32. with -lt: sort by, and show, access time; with -l: show access time and sort by name; otherwise: sort by access time 

  33. do not sort; list entries in directory order 

  34. natural sort of (version) numbers within text 

  35. --width 

  36. list entries by lines instead of by columns 

  37. sort alphabetically by entry extension 

  38. --context 

  39. list one file per line 

  40. touch (GNU coreutils) 8.22 touch --help 参照 

  41. アクセス日時のみ変更する 

  42. --no-create 

  43. --date 

  44. (無視される) 

  45. --no-dereference 

  46. 更新日時のみ変更する 

  47. --reference 

  48. use [[CC]YY]MMDDhhmm[.ss] instead of current time 

  49. cp (GNU coreutils) 8.22 cp --help 参照 

  50. --archive 

  51. --backup と同様だが引数を受け付けない 

  52. deprecated, same as --preserve=context 

  53. --no-dereference --preserve=links と同様 

  54. --force 

  55. follow command-line symbolic links in SOURCE 

  56. --interactive 

  57. --link 

  58. --no-clobber 

  59. --preserve=mode,ownership,timestamps と同様 

  60. --no-dereference 

  61. --symbolic-link 

  62. --target-directory 

  63. --no-target-directory 

  64. --update 

  65. --verbose 

  66. --one-file-system 

  67. set SELinux security context of destination file to default type 

  68. mv (GNU coreutils) 8.22 mv --help 参照 

  69. --backup と同様だが引数を受け付けない 

  70. --suffix 

  71. mkdir (GNU coreutils) 8.22 mkdir --help 参照 

  72. --mode 

  73. --parents 

  74. set SELinux security context of each created directory to the default type 

  75. rmdir (GNU coreutils) 8.22 rmdir --help 参照 

  76. chown (GNU coreutils) 8.22 chown --help 参照 

  77. --changes 

  78. --silent, --quiet 

  79. if a command line argument is a symbolic link to a directory, traverse it 

  80. traverse every symbolic link to a directory encountered 

  81. do not traverse any symbolic links (default) 

  82. chmod (GNU coreutils) 8.22 chmod --help 参照 

  83. cat (GNU coreutils) 8.22 cat --help 参照 

  84. --show-all 

  85. --number-nonblank 

  86. -vEと同じ 

  87. --show-ends 

  88. --number 

  89. --squeeze-blank 

  90. -vTと同じ 

  91. --show-tabs 

  92. (無視) 

  93. --show-nonprinting 

  94. head (GNU coreutils) 8.22 head --help 参照 

  95. --bytes 

  96. --lines 

  97. --quiet, --silent 

  98. tail (GNU coreutils) 8.22 tail --help 参照 

  99. --follow 

  100. same as --follow=name --retry 

  101. --sleep-interval 

  102. wc (GNU coreutils) 8.22 wc --help 参照 

  103. --lines 

  104. --max-line-length 

  105. --chars 

  106. --words 

  107. sort (GNU coreutils) 8.22 sort --help 参照 

  108. --ignore-leading-blanks 

  109. --check 

  110. -c と同様だが、正しくソートされていない最初の行を出力しない 

  111. --dictionary-order 

  112. --ignore-case 

  113. --general-numeric-sort 

  114. --human-numeric-sort 

  115. --ignore-nonprinting 

  116. --key 

  117. --merge 

  118. --month-sort 

  119. --numeric-sort 

  120. --output 

  121. --reverse 

  122. --random-sort 

  123. --stable 

  124. --buffer-size 

  125. --field-separator 

  126. --temporary-directory 

  127. --unique 

  128. --version-sort 

  129. --zero-terminated 

  130. uniq (GNU coreutils) 8.22 uniq --help 参照 

  131. --count 

  132. --repeated 

  133. --all-repeated 

  134. --skip-fields 

  135. --ignore-case 

  136. --skip-chars 

  137. --check-chars 

  138. diff (GNU diffutils) 3.3 diff --help 参照 

  139. --text 

  140. --ignore-space-change 

  141. --ignore-blank-lines 

  142. --context 

  143. --minimal 

  144. --ifdef 

  145. --ed 

  146. --ignore-tab-expansion 

  147. --show-function-line 

  148. --ignore-matching-lines 

  149. --paginate 

  150. --rcs 

  151. --new-file 

  152. --show-c-function 

  153. --brief 

  154. --report-identical-files 

  155. --starting-file 

  156. --expand-tabs 

  157. --initial-tab 

  158. --unified 

  159. --version 

  160. --ignore-all-space 

  161. --exclude 

  162. --exclude-from 

  163. --side-by-side 

  164. --ignore-trailing-space 

  165. grep (GNU grep) 2.20 grep --help 参照 

  166. --after-context 

  167. --byte-offset 

  168. --before-context 

  169. --directories 

  170. --devices 

  171. --regexp 

  172. --extended-regexp 

  173. --file 

  174. --fixed-strings 

  175. basic-regexp 

  176. --no-filename 

  177. --with-filename 

  178. equivalent to --binary-files=without-match 

  179. --files-with-matches 

  180. --files-without-match 

  181. --max-count 

  182. --line-number 

  183. --only-matching 

  184. --perl-regexp 

  185. --dereference-recursive 

  186. --no-messages 

  187. --unix-byte-offsets 

  188. --binary 

  189. --invert-match 

  190. --word-regexp 

  191. --line-regexp 

  192. --null-data 

  193. --null 

  194. curl 7.29.0 (x86_64-redhat-linux-gnu) libcurl/7.29.0 NSS/3.44 zlib/1.2.7 libidn/1.28 libssh2/1.8.0 curl --help 参照 

  195. --append 

  196. --user-agent 

  197. --cookie 

  198. --use-ascii 

  199. --cookie-jar 

  200. --continue-at 

  201. --data 

  202. --dump-header 

  203. --referer 

  204. --cert 

  205. --fail 

  206. --form 

  207. --globoff 

  208. --get 

  209. --help 

  210. --header 

  211. --include 

  212. --head 

  213. --junk-session-cookies 

  214. --remote-header-name 

  215. --insecure 

  216. --config 

  217. --list-only 

  218. --location 

  219. --max-time 

  220. --manual 

  221. --netrc 

  222. --no-buffer 

  223. --remote-name 

  224. --proxytunnel 

  225. --ftp-port 

  226. If used as the first parameter disables .curlrc 

  227. --quote 

  228. --range 

  229. --remote-time 

  230. --silent 

  231. --show-error 

  232. --telnet-option 

  233. --upload-file 

  234. --user 

  235. --proxy-user 

  236. --write-out 

  237. --proxy 

  238. --request 

  239. --speed-time 

  240. --speed-limit 

  241. --time-cond 

  242. --http1.0 

  243. --tlsv1 

  244. --sslv2 

  245. --sslv3 

  246. --ipv4 

  247. --ipv6 

  248. --progress-bar 

  249. tar (GNU tar) 1.26 tar --help 参照 

  250. --auto-compress 

  251. --catenate, --concatenate 

  252. --blocking-factor 

  253. --read-full-records 

  254. --create 

  255. --directory 

  256. --diff, --compare 

  257. --info-script 

  258. --listed-incremental 

  259. --incremental 

  260. --dereference 

  261. --format 

  262. --ignore-zeros 

  263. --use-compress-program 

  264. --bzip2 

  265. --xz 

  266. --keep-old-files 

  267. --starting-file 

  268. --check-links 

  269. --tape-length 

  270. --touch 

  271. --multi-volume 

  272. --seek 

  273. --newer 

  274. 作成時は --old-archive と同じ. 抽出時は--no-same-owner と同じ 

  275. --to-stdout 

  276. --preserve-permissions, --same-permissions 

  277. --absolute-names 

  278. --append 

  279. --block-number 

  280. --preserve-order, --same-order 

  281. --sparse 

  282. --list 

  283. --files-from 

  284. --unlink-first 

  285. --label 

  286. --interactive, --confirmation 

  287. --verify 

  288. --extract, --get 

  289. --gzip, --gunzip, --ungzip 

  290. --compress, --uncompress 

  291. --help 

  292. gzip 1.5 gzip --help 参照 

  293. --stdout 

  294. --decompress 

  295. --list 

  296. --license 

  297. --no-namet 

  298. --name 

  299. --quiet 

  300. --test 

  301. --fast 

  302. --best 

  303. kill from util-linux 2.23.2 /bin/kill --help 参照 

  304. --table 

  305. --pid 

  306. --queue 

  307. --signal 

  308. df (GNU coreutils) 8.22 df --help 参照 

  309. --block-size 

  310. --si 

  311. --inodes 

  312. --block-size=1K と同様 

  313. --local 

  314. --portability 

  315. --type 

  316. --print-type 

  317. (ignored) 

  318. --exclude-type 

  319. free from procps-ng 3.3.10 free --help 参照 

  320. --bytes 

  321. --giga 

  322. --human 

  323. --kilo 

  324. --lohi 

  325. --mega 

  326. --seconds 

  327. --total 

  328. --wide 

  329. vmstat from procps-ng 3.3.10 vmstat --help 参照 

  330. --active 

  331. --disk 

  332. --disk-sum 

  333. --forks 

  334. --slabs 

  335. --one-header 

  336. --partition 

  337. --stats 

  338. --unit 

  339. --timestamp 

  340. git version 2.25.1 git clone -h 参照 

  341. --branch 

  342. --config 

  343. --jobs 

  344. --no-checkout 

  345. --origin 

  346. --shared 

  347. --upload-pack 

  348. git version 2.25.1 git init -h 参照 

  349. git version 2.25.1 git add -h 参照 

  350. --edit 

  351. --dry-run 

  352. --intent-to-add 

  353. --patch 

  354. git version 2.25.1 git mv -h 参照 

  355. skip move/rename errors 

  356. git version 2.25.1 git restore -h 参照 

  357. --source 

  358. --staged 

  359. --worktree 

  360. --ours 

  361. --theirs 

  362. git version 2.25.1 git rm -h 参照 

  363. allow recursive removal 

  364. git version 2.25.1 git diff -h 参照 

  365. --break-rewrites 

  366. --find-copies 

  367. --irreversible-delete 

  368. look for differences that change the number of occurrences of the specified regex 

  369. prevent rename/copy detection if the number of rename/copy targets exceeds given limit 

  370. --find-renames 

  371. control the order in which files appear in the output 

  372. swap two inputs, reverse the diff 

  373. --no-patch 

  374. look for differences that change the number of occurrences of the specified string 

  375. generate patch 

  376. --function-context 

  377. --dirstat 

  378. do not munge pathnames and use NULs as output field terminators in --raw or --numstat 

  379. git version 2.25.1 git grep -h 参照 

  380. match <pattern> 

  381. read patterns from file 

  382. don't show filenames 

  383. show filenames 

  384. don't match patterns in binary files 

  385. --open-files-in-pager 

  386. --show-function 

  387. git version 2.25.1 git log -h 参照 

  388. Process line range n,m in file, counting from 1 

  389. git version 2.25.1 git show -h 参照 

  390. Process line range n,m in file, counting from 1 

  391. git version 2.25.1 git status -h 参照 

  392. --short 

  393. --untracked-files 

  394. git version 2.25.1 git branch -h 参照 

  395. --copy 

  396. copy a branch, even if target exists 

  397. --delete 

  398. delete branch (even if not merged) 

  399. --move 

  400. move/rename a branch, even if target exists 

  401. --remotes 

  402. --track 

  403. --set-upstream-to 

  404. git version 2.25.1 git commit -h 参照 

  405. --reedit-message 

  406. --reuse-message 

  407. --message 

  408. --no-verify 

  409. --only 

  410. --signoff 

  411. --gpg-sign 

  412. --template 

  413. git version 2.25.1 git merge -h 参照 

  414. do not show a diffstat at the end of the merge 

  415. --strategy 

  416. --strategy-option 

  417. git version 2.25.1 git rebase -h 参照 

  418. passed to 'git apply' 

  419. --force-rebase 

  420. --keep-empty 

  421. --no-stat 

  422. --rebase-merges 

  423. --exec 

  424. git version 2.25.1 git reset -h 参照 

  425. git version 2.25.1 git switch -h 参照 

  426. --force-create 

  427. --detach 

  428. git version 2.25.1 git tag -h 参照 

  429. --annotate 

  430. print <n> lines of each tag message 

  431. --sign 

  432. --local-user 

  433. --verify 

  434. git version 2.25.1 git fetch -h 参照 

  435. --keep 

  436. --multiple 

  437. do not fetch all tags (--no-tags) 

  438. --server-option 

  439. --prune 

  440. --prune-tags 

  441. --tags 

  442. --update-head-ok 

  443. git version 2.25.1 git pull -h 参照 

  444. do not show a diffstat at the end of the merge 

  445. --rebase 

  446. git version 2.25.1 git push -h 参照 

  447. --push-option 

  448. --set-upstream 

  449. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker build --help 参照 

  450. --cpu-shares 

  451. --memory 

  452. --tag 

  453. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker commit --help 参照 

  454. --author 

  455. --change 

  456. --pause 

  457. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker cp --help 参照 

  458. --follow-link 

  459. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker create --help 参照 

  460. --attach 

  461. --env 

  462. --hostname 

  463. --label 

  464. --publish 

  465. --publish-all 

  466. --tty 

  467. --volume 

  468. --workdir 

  469. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker events --help 参照 

  470. --filter 

  471. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker exec --help 参照 

  472. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker export --help 参照 

  473. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker history --help 参照 

  474. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker images --help 参照 

  475. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker import --help 参照 

  476. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker info --help 参照 

  477. --format 

  478. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker inspect --help 参照 

  479. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker kill --help 参照 

  480. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker load --help 参照 

  481. --input 

  482. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker login --help 参照 

  483. --password 

  484. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker logs --help 参照 

  485. --timestamps 

  486. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker ps --help 参照 

  487. --latest 

  488. --last 

  489. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker pull --help 参照 

  490. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker restart --help 参照 

  491. --time 

  492. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker rm --help 参照 

  493. --volumes 

  494. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker rmi --help 参照 

  495. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker run --help 参照 

  496. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker save --help 参照 

  497. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker search --help 参照 

  498. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker start --help 参照 

  499. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker stats --help 参照 

  500. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker stop --help 参照 

  501. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker update --help 参照 

  502. Client: Docker Engine - Community; Version: 19.03.8; API version: 1.40; docker version --help 参照 

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

RootlessモードのDockerを試してみた

Docker 19.03で入った新機能であるDockerのRootlessモードを試してみました。

Rootlessモードとは

従来はroot権限でdockerデーモンを実行していたために、脆弱性やdockerソケットを渡すなどの設定ミスをしているとホストのroot権限を奪われてしまう可能性がありました。

Rootlessモードでは各ユーザでdockerデーモンを実行するため、脆弱性などがあった場合でもそのユーザの権限内でしか影響がなくなります(まあ、各ユーザから権限昇格されたら別でしょうが)。

RootlessモードのDockerをインストールする

実際にRootlessモードのDockerをインストールしてみます。

試した環境は以下のようになっています。

OS : Ubuntu 18.04(Hyper-V上)
Memory : 2GB
CPU : Intel Core i9
docker-composeインストール済み

  1. インストールコマンドを実行する

    $ curl -fsSL https://get.docker.com/rootless | sh
    
  2. .bashrcに追加を行う

    インストールしたRootlesモードDockerバイナリとソケットのパスを.bashrcに記述します。インストールしたときにコンソール上に記述されている内容をコピペすればOKです。

    export PATH=$HOME/bin:$PATH
    export DOCKER_HOST=unix:///run/user/1000/docker.sock
    
  3. 自動起動の設定を行う

    最後にRootlessモードのDockerの起動設定を行います。これはsystemctlで行います。

    $ systemctl --user enable docker
    $ systemctl --user start docker
    

実際にコマンドを実行してみる

単一コンテナの実行

まずは順当にhello-worldのコンテナを実行してみましょう。

$ docker run -it --rm hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
0e03bdcc26d7: Pull complete
Digest: sha256:8e3114318a995a1ee497790535e7b88365222a21771ae7e53687ad76563e8e76
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

おお、sudoコマンドを使わずに行けました。

単一コンテナでポートを公開する

では、WEBサーバとして外部にポートを公開するコンテナを作ってみましょう。

昔、Dockerのポート公開はiptablesを使用してforwardしていると聞いたことがあるので、ここはさすがにいけないでしょうと思っていますが。

$ docker run -d --rm -p 80:80 nginx:1.17-alpine
Unable to find image 'nginx:1.17-alpine' locally
1.17-alpine: Pulling from library/nginx
cbdbe7a5bc2a: Pull complete
c554c602ff32: Pull complete
Digest: sha256:763e7f0188e378fef0c761854552c70bbd817555dc4de029681a2e972e25e30e
Status: Downloaded newer image for nginx:1.17-alpine
45bc78be4cc1d2f35321ae80ea3d9fe82cfc3b545a17f16b2eb1c3ea81e5a535
docker: Error response from daemon: driver failed programming external connectivity on endpoint youthful_einstein (9fddff03eda43e5fc3d29328cc20040d5a1a57168bd2fcd7d08473f2a2af6e9d): Error starting userland proxy:.

やっぱり駄目でした。。。

エラーメッセージからするとポート公開を設定しようとして、エラーになったようですね。

docker-composeを使ってみる

では、docker-composeで複数のコンテナを起動してみましょう。

以下の内容でdocker-compose.ymlを書きました。今回はとりあえず、giteaが動けばいいな~と思っています。

docker-compose.yml
version: "3.7"
services:
  server:
    image: gitea/gitea:latest
    environment:
      - USER_UID=1000
      - USER_GID=1000
      - DB_TYPE=postgres
      - DB_HOST=db:5432
      - DB_NAME=gitea
      - DB_USER=gitea
      - DB_PASSWORD=gitea
      - DISABLE_SSH=false
    restart: always
    networks:
      - gitea
    volumes:
      - ./gitea:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - 3000:3000
    depends_on:
      - db
  db:
    image: postgres:11-alpine
    restart: always
    environment:
      - POSTGRES_USER=gitea
      - POSTGRES_PASSWORD=gitea
      - POSTGRES_DB=gitea
    networks:
      - gitea
    volumes:
      - ./postgres:/var/lib/postgresql/data
networks:
  gitea:
    external: false

先ほどの例からするとポート公開で失敗しそうですが、とりあえず実行してみます。。。

$ docker-compose up -d
Creating network "foo_gitea" with the default driver
Creating foo_db_1 ... done
Creating foo_server_1 ... done
$ docker-compose ps
      Name                     Command               State               Ports
-------------------------------------------------------------------------------------------
foo_db_1       docker-entrypoint.sh postgres    Up      5432/tcp
foo_server_1   /usr/bin/entrypoint /bin/s ...   Up      22/tcp, 0.0.0.0:3000->3000/tcp

どうも、うまく動いていそうですね。

では、ブラウザから見てみましょう。

image.png

出ましたね。

まとめ

RootlessモードのDockerは単一で実行するようなもの(バッチ処理とか)には向いていそうです。
docker-composeでのポート公開とdockerコマンドでのポート公開で挙動が異なるのがかなり気になりますが、docker-composeを使えばWebアプリの開発環境でも使えそうです。

それにしても、docker-composeのポート公開はどのようにして実現しているのでしょう??不思議でたまりません。どなたかご存じないでしょうか?

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