AI can fly !!

AI がやりたい Web エンジニアのアウトプット (AI の知識は無い)

【Docker】初心者のための Docker Compose まとめ

docker-logo

更新履歴

2023/05/05

Docker Compose CLI を Docker CLI の Compose V2 へ変更

はじめに

2021 年現在、本番環境や開発環境を問わず Docker (コンテナ技術) は当たり前のものとして使用されるようになりました。

いちエンジニアの立場としても、開発環境をコンテナでスピーディに構築するだけでなく、ちょっとしたお試し環境を用意したいときなど、手軽に環境を Scrap and build できる Docker はもはや無くてはならない存在です。

Docker Compose の詳細については Docker 公式ドキュメントの Docker Compose のページ を参照いただくとして、当記事では Docker 初心者が Docker Compose を使用するにあたり、よく使うんだけどまだちゃんと覚えていない…というような内容をまとめました。

当記事でゼロから Docker Compose を学ぶということではなく、 Docker Compose を一通り学んだ初心者がリファレンス的に使用することを想定しています。

慣れてしまえば難しいことはありませんが、そもそも Docker とは、コンテナ技術とは、という部分が不安な方は Docker 公式ドキュメント を一読することをお勧めします。

ただし、 Docker 公式ドキュメントを一読したなら、そもそもこの記事を読む必要は無いと思いますけどね…

動作環境

OS Version
Ubuntu 22.04.2 LTS

Windows 10 Pro の Windows Subsystem for Linux (WSL 2) を使用

Docker Products Version
Docker Engine 23.0.5
Docker Compose v2.17.3

Docker Compose まとめ

前述した通り、 Docker Compose についての詳細は Docker 公式ドキュメントをご参照ください。

docs.docker.com

ざっくりと超訳すれば、 Docker Compose は複数のコンテナをまとめて定義・管理することができる Docker のためのツールです。

Compose ファイル (docker-compose.yml)

version: '3.8'

services:
  [service_name]:
    build: [context_path]
    image: [image_name]:[tag_name]
    container_name: [container_name]
    command: [command]
    environment:
      [variable_name]: [value]
    volumes:
      - [volume_name]:[container_directory_path]:[mode]
      - [host_directory_path]:[container_directory_path]:[mode]
      - type: volume
        source: [volume_name]
        target: [container_directory_path]
      - type: bind
        source: [host_directory_path]
        target: [container_directory_path]
    networks:
      - [network_name]
    ports:
      - '[host_port]:[container_port]'
    tty: [boolean]
    restart: [restart_policy]
    depends_on:
      - [other_service_name]
  [other_service_name]:
    ...

volumes:
  [volume_name]:

networks:
  [network_name]:

Compose ファイルには、 Docker Compose で実行する Docker アプリケーションの設定を定義します。

ファイルは YAML 形式で記述しますが、 JSON 形式でも記述可能です。

コンテナ (services) だけでなく、各コンテナ間のネットワーク (networks) やボリューム (volumes) についても定義でき、各セクションの設定項目は多岐にわたります。

ここでは、 (僕が) よく使用する項目を中心に記載しました。

version (Compose ファイルフォーマットのバージョン)

version: "3.8"

Compose ファイルフォーマットのバージョンを指定します。

使用する Docker Engine のバージョン毎にサポートされる Compose ファイルフォーマットのバージョンが異なるので、 Docker Engine のバージョンに合わせて Compose ファイルのバージョンを指定する必要があります。

以下はその一例です。

Compose file format Docker Engine release
3.8 19.03.0+
3.7 18.06.0+
3.0 1.13.0+

※ 注意点として、 Compose ファイルのバージョンを指定する場合は、メジャーバージョンとマイナーバージョンの両方を明示的に記述 (version: "3.8") する必要があります。 もしメジャーバージョンのみを記述した場合、マイナーバージョンは最新バージョンではなくデフォルトの 0 が補完されます。 (version: "3.0")

docs.docker.com

services セクション

services:

サービス (コンテナ) を定義します。

services セクション直下に複数のサービスを列記することができます。

[service_name] (サービス名)

  [service_name]:

  # e.g.
  web:

サービスの名前を指定します。

後述する buildimage で構築される Docker イメージに名前を付けていない場合、構築されるイメージ名は [project_name]_[service_name] になります。

プロジェクト名 (project_name) が特に指定されていない場合は、 Compose ファイルが配置されているディレクトリ名がプロジェクト名になります。

build (Dockerfile)
    build: [context_path]

    # e.g.
    build: .

build の指定方法の一つとして、 Dockerfile を含むディレクトリのパスを指定します。

Dockerfile のファイル名やビルド引数などの詳細を指定する方法もありますが、今回は割愛します。

後述する image を指定することで、構築される Docker イメージに名前を付けることができます。

Dockerfile については 別記事 にまとめていますので、そちらをご覧ください。

ai-can-fly.hateblo.jp

image (Docker イメージ名)
    image: [image_name]:[tag_name]

    # e.g.
    image: python-flask:latest

コンテナで起動する Docker イメージを指定します。

前述の build が指定されている場合は、 build で指定された Dockerfile から Docker イメージが構築され、そのイメージ名が image で指定した名前になります。

build を指定しない (Dockerfile からイメージを構築しない) 場合、ここで指定された Docker イメージからコンテナを作成しますが、指定した Docker イメージがローカルに存在しない場合は、 Docker Hub から Pull (取得) した上でコンテナが作成されます。

container_name (Docker コンテナ名)
    container_name: [container_name]

    # e.g.
    container_name: python-flask

構築された Docker イメージから作成されるコンテナの名前を指定します。

command (コマンド)
    command: [command]

    # e.g.
    command: flask run

Docker Compose でコンテナを開始する際に実行されるコマンドを指定します。

build セクションや image セクションの Dockerfile や Docker イメージで定義されている CMD に代わり、ここで指定したコマンドが実行されます。

environment (環境変数)
    environment:
      [variable_name]: [value]

    # e.g.
    environment:
      FLASK_ENV: development
      SECRET_KEY

コンテナで使用する環境変数を指定します。

環境変数名のみを指定した場合、 Docker Compose が起動しているシェルで定義されている同名の環境変数がコンテナへ渡されます。

注意点として、 build セクションで Dockerfile をビルドする際はここで指定した環境変数は使用できません。

ビルド時の環境変数build セクションのサブセクションである args セクションで指定します。

volumes (ボリューム)
    volumes:
      - [volume_name]:[container_directory_path]:[mode]
      - [host_directory_path]:[container_directory_path]:[mode]
      - type: volume
        source: [volume_name]
        target: [container_directory_path]
      - type: bind
        source: [host_directory_path]
        target: [container_directory_path]

    # e.g.
    volumes:
      - ./src:/src:rw

コンテナで使用するボリュームを指定します。

ボリュームの指定には、 type (ボリュームのマウント種類) などを省略して一行で書く方法と、詳細を複数行にわたって細かく指定する二通りの書き方があります。

type source target
volume volumes セクションで定義した名前付きボリューム ([volume_name]) を指定 ボリュームがマウントされるコンテナのパス ([container_directory_path]) を指定
bind ホストマシンのパス ([host_directory_path]) を指定 ボリュームがマウントされるコンテナのパス ([container_directory_path]) を指定
tmpfs - ボリュームがマウントされるコンテナのパス ([container_directory_path]) を指定

bind で指定するホストマシンのパス ([host_directory_path]) には、 Compose ファイルからの相対パス (./) やユーザのホームディレクトリからの相対パス (~/) が指定できます。

コンテナのパス ([container_directory_path]) に Docker イメージに存在しないディレクトリを指定した場合、自動的に当該ディレクトリ (親パス含む) が作成され、ボリュームがマウントされます。

一行で指定する場合の mode には、読み取り専用の ro と読み書き可の rw が指定でき、省略時のデフォルトは rw になります。

Bind mounts の注意点

マウントするホスト側のディレクトリとマウントされるコンテナ側のディレクトリのいずれかが空でない場合、ホスト側のディレクトリが優先されることになります。

Host side directory Container side directory Mounted result
空になる
空でない ホスト側のディレクトリ内のデータがマウントされる
空でない 空になる
空でない 空でない ホスト側のディレクトリ内のデータがマウントされる

簡単に言ってしまえば、一部の例外的な Docker イメージを除き、常にホスト側のディレクトリでコンテナ側のディレクトリが置き換わります。

これはディレクトリの統合 (merge) ではないため、たとえホスト側のディレクトリが空であっても、コンテナ側のディレクトリ内のファイル有無に関わらず、結果としてコンテナ内のマウント先ディレクトリは空になります。

誤ってマウント先のファイルを消してしまうことがないように注意しましょう。

ただ、間違った設定をしてしまったとしても、 Compose ファイルを修正して再度コンテナを作成すれば問題ありません。

これも Scrap and build が容易な Docker の良いところです。

networks (ネットワーク)
    networks:
      - [network_name]

コンテナが接続するネットワークを指定します。

後述する最上位の networks セクションで定義したネットワークを指定することで、明示的にコンテナが接続するネットワークを選択できます。

独自のネットワーク設定を行わなかった場合、コンテナは既定のネットワーク ([project_name]_default) に接続され、各サービスのコンテナ間は [service_name] をホスト名としてアクセスすることができます。

ports (ポート)
    ports:
      - "[host_port]:[container_port]"

    # e.g.
    ports:
      - "5000:5000"

ホスト側ポートとコンテナ側ポートのマッピングを指定します。

コンテナ側のポート番号のみを指定した場合、ホスト側のポート番号は空ポートが自動的に割り当てられます。

注意点として、設定にもよりますが、コンテナ内で起動した開発サーバなどが localhost (127.0.0.1) からの接続のみを許可している場合、ホスト側から localhost (127.0.0.1) で接続することができないことがあります。

これはホスト側からポートフォワードされた際、 localhost (127.0.0.1) がコンテナ内の OS の IP アドレスに変換され、外部 (localhost (127.0.0.1) 以外) からのアクセスと判断されてしまうためで、解決策としてコンテナ内で起動するサーバへのアクセス制限を無くす必要があります。

tty (疑似 TTY)
    tty: [boolean]

疑似 TTY の割り当てを指定します。

true を指定すると、コンテナを開始時に疑似 TTY が割り当てられます。

restart (サービス再起動ポリシー)
    restart: [restart_policy]

サービスの再起動ポリシーを指定します。

ここでは、 Docker を起動した際にコンテナを自動的に開始するかどうかを制御することができます。

Restart policies Description
"no" 自動でコンテナを開始しない (既定値)
always 常にコンテナを開始する
on-failure エラー発生によりコンテナが終了した場合、コンテナを開始する
unless-stopped コンテナを手動等で停止した場合を除き、常にコンテナを開始する

いずれの場合も、手動でコンテナを停止した直後にコンテナが再起動することはありません。

alwaysunless-stopped の違いは、手動でコンテナを停止した後、 Docker の (再) 起動時にコンテナが自動的に開始されるかどうかになります。

depends_on (サービス間の依存関係)
    depends_on:
      - [other_service_name]

サービス間の依存関係を定義します。

ここで他サービスを指定した場合、 docker-compose up コマンドによるコンテナの開始時、依存する他サービス ([other_service_name]) のコンテナを開始してから当サービス ([service_name]) のコンテナを開始します。

また、 docker-compose stop コマンドによるコンテナの停止時も、依存する他サービスのコンテナが停止してから当サービスのコンテナを停止します。

volumes セクション

volumes:
  [volume_name]:

サービスで使用するボリュームを定義します。

volumes セクション直下に列記した名前付きボリュームは、前述した services セクションの各サービスの volumes に指定して使用できます。

詳細な設定については、今回は割愛します。

networks セクション

networks:
  [network_name]:

サービスで使用するネットワークを定義します。

networks セクション直下に列記したネットワークは、前述した services セクションの各サービスの network に指定して使用できます。

詳細な設定については、今回は割愛します。

Docker CLI (Compose V2)

docker compose [options] [command] [arguments]

Compose ファイルに定義された複数のサービスは、 docker compose コマンドで一括、または個別に操作することができます。

既定ではカレントディレクトリにある docker-compose.yml を Compose ファイルとして使用しますが、以下の -f オプションを使用すれば、任意の場所にある Compose ファイルを指定することができます。

Options Description Example
-f [compose file] 任意の Compose ファイルを指定。 -f ./others/docker-compose-sub.yml
--compatibility 各サービスの deploy セクションの内容を読み取り、 Compose ファイルのバージョン 2 のパラメータとして変換・実行する。 --compatibility

build (イメージ構築)

docker compose build [options] [service]

Compose ファイルに定義された各サービスの Docker イメージを構築します。

サービスの Dockerfile やイメージ構築時のディレクトリ構成・内容を変更した場合は、 docker compose build コマンドでイメージを再構築する必要があります。

Options Description
--no-cache イメージ構築時に、イメージのキャッシュを使用しない。

run (コンテナを開始してコマンド実行)

docker compose run [option] [service] [command] [arguments]

Compose ファイルに定義されたサービスのコンテナを開始し、開始したコンテナ内でコマンドを実行します。

run サブコマンドではサービスの指定は必須です。

イメージが存在しない場合は、合わせて構築されます。

オプションを指定しない場合、デフォルトでは以下の動作となります。

  • Compose ファイルのサービスで定義されたコマンドを実行するが、 run コマンドで実行するコマンドを指定した場合、コンテナ内で実行されるコマンドを上書きすることが可能
  • Compose ファイルのサービスで定義されたポートを作成しない
  • 疑似ターミナル (TTY) が割り当てられる
Options Description Example
--name 開始するコンテナに名前を設定。 --name container_name
-d コンテナをバックグラウンドで実行。 -d
--rm コンテナを実行後に削除。バックグラウンドで実行した場合は無視される。 --rm
--service-ports Compose ファイルで定義したポートを作成。 --service-ports
-p, --publish コンテナのポートをホストへ公開。 -p 8080:80
-T 疑似ターミナル (TTY) を割り当てしない。 -T

start (コンテナ開始)

docker compose start [service]

サービスのコンテナを開始します。

stop (コンテナ停止)

docker compose stop [service]

稼働中のサービスのコンテナを削除せずに停止します。

停止したサービスのコンテナは、 start コマンドで再度開始できます。

restart (コンテナ再起動)

docker compose restart [service]

停止中・実行中にかかわらず、 Compose ファイルで定義されたサービスのコンテナすべてを再起動します。

注意点として、 Compose ファイルを変更して restart コマンドを実行しても、変更内容はコンテナには反映されません。

rm (コンテナ削除)

docker compose rm [option] [service]

Compose ファイルで定義された停止中のサービスのコンテナを削除します。

デフォルトでは、コンテナにアタッチした匿名ボリュームは削除されません。

Options Description
-v コンテナにアタッチした匿名ボリュームを削除。

up (イメージ構築、コンテナ作成・開始・アタッチ)

docker compose up [option] [service]

Compose ファイルで定義されたサービスのイメージの構築、コンテナの作成・開始・アタッチを行います。

もし、既に存在するコンテナのサービスの設定やイメージが変更されていた場合、設定を反映するためにコンテナの停止・再作成が行われます。

Options Description
-d コンテナをバックグラウンドで実行。
--force-recreate Compose ファイルや使用されるイメージに変更が無くても、コンテナを再作成。
--no-recreate コンテナが存在する場合、再作成しない。
--no-build イメージを構築しない。イメージが存在しない場合はエラー。
--build イメージを構築後、コンテナを開始。イメージに変更があれば、コンテナは再作成される。
--no-start コンテナを開始しない。

down (コンテナ停止・削除)

docker compose down [options]

Compose ファイルで定義されたサービスのコンテナを停止し、 up コマンドで作成されたイメージ・コンテナ・ネットワーク・ボリュームを削除します。

オプションを指定しなければ、デフォルトで削除されるのは以下のコンテナとネットワークのみです。

  • Compose ファイルで定義されたサービスのコンテナ
  • Compose ファイルの network セクションで定義されたネットワーク
  • default ネットワーク(使用している場合のみ)
Options Description Example
--rmi [type] イメージを削除。 type に all を指定するとすべてのイメージを、 local を指定すると image フィールドにカスタムタグのないイメージだけを削除します。 --rmi all
-v, --volumes volumes セクションの名前付きボリューム、および、コンテナにアタッチした匿名ボリュームを削除。 -v

exec (稼働中のコンテナでコマンド実行)

docker compose exec [options] [service] [command] [arguments]

Compose ファイルで定義されたサービスの稼働中のコンテナ内で、指定したコマンドを実行します。

コンテナが開始していない場合は、コマンドは実行されません。

exec サブコマンドではサービスの指定は必須です。

オプションを指定しない場合、デフォルトでは疑似ターミナル (TTY) が割り当てられます。

Options Description Example
-d, --detach コマンドをバックグラウンドで実行。 -d
-T 疑似ターミナル (TTY) を割り当てしない。 -T
-e, --env 環境変数を設定。 -e KEY=value
-w, --workdir コマンドを実行するディレクトリを指定。 -w /path/to/workdir

ps (コンテナ一覧表示)

docker compose ps [options] [service]

Compose ファイルで定義されたサービスのコンテナを一覧表示します。

オプションを指定しなければ、デフォルトで表示されるのは稼働中のコンテナのみです。

Options Description
-q, --quiet コンテナ ID のみを表示。
--services コンテナのサービス名を表示。
-a, --all 停止中のコンテナを含んだすべてのコンテナを表示。

logs (ログ表示)

docker compose logs [options] [service]

Compose ファイルで定義されたサービスのログを表示します。

Options Description
-f, --follow ログを出力し続けます。ログ出力の停止は Ctrl + C で行います。
-t, --timestamps ログにタイムスタンプを出力します。

おわりに

とりあえず Docker Compose を使用するだけなら今回まとめた内容で事足りると思いますが、 Docker Compose は Dockerfile ほどではないにせよ奥が深く、より効率良く運用するためには Docker 公式ドキュメント をしっかり理解する必要があります。

また、 Docker が登場してから既に 8 年以上が経過し、その間、既に非推奨になった内容や新たに追加された仕様も複数存在します。

今回は Docker 公式ドキュメントを参考にしつつ 2021 年 8 月現在の最新情報でまとめたつもりなので、これから Docker Compose を本格的に使用しようと考えている方は、いったんここで最低限必要な内容を押さえ、あとは使いながら深い内容をキャッチアップしていっていただければと思います。

と、これまでさも知っている風に色々書いてきましたが、僕が Docker を使い始めたのは今年からになります。

はい、僕も完全に初心者ですね。イキりました。すいません _(┐「ε¦)_

【Angular】angular-gridster2 の使い方をまとめてみた (日本初かもしれない)

Angular

はじめに

Angular で Windows 10 のスタートメニューにあるような Drag and Drop ができるタイルを実装するにあたり、何か良さげなパッケージが無いか探していたところ、 angular-gridster2 というパッケージを教えてもらったので、その使い方を調べてみました。

github.com

angular-gridster2 は Drag and Drop で移動可能なタイル群を Grid Layout で配置でき、タイルの追加・削除・リサイズも簡単に実装することができる素敵パッケージです。

また、オプションやイベントが複数用意されているため、行数・列数の上限やタイル周囲の margin などの細かい指定のほか、ユーザの操作に応じたコールバック関数の実行も可能です。

ライセンスは MIT License なので、著作権表示および本許諾表示といったルールさえ順守すれば商用利用も問題ありません。

そんな魅力あふれるパッケージではありますが、色々調べる中で直面した大きな問題が…

それは、日本語で書かれたドキュメントが皆無だということ!!

使い方は難しくないですが、 GitHub の公式リポジトリ公式 Demo サイト を参考にしつつ、実際にコードを書いて動かしながら記事にまとめるのはなかなか大変でした。。

tiberiuzuld.github.io

もしかしたら、この記事が angular-gridster2 を日本語で取り上げた最初のエントリーかもしれません!?

動作環境

OS Version
Ubuntu 20.04 LTS

Windows 10 Pro の Windows Subsystem for Linux (WSL 2) を使用

Environment Version
Node.js 14.17.0
npm 6.14.13
Package Version
@angular/cli 12.1.2
angular-gridster2 12.1.0

前提条件

  • Angular CLI がインストールされている
  • Angular CLI を使用した Angular アプリケーションが作成されている

angular-gridster2 概論

導入

インストール

npm install angular-gridster2 --save

インストールは npm でサクッと行います。

--save オプションって、いつの間にか指定しなくてもデフォルトで ON になっていたらしい…

知らなかった… (npm 5.0.0 以降だそうです)

使い方

NgModule (app.module.ts)

...
import { GridsterModule } from 'angular-gridster2';

@NgModule({
  ...
  imports: [
    ...
    GridsterModule,
  ],
})
export class AppModule {}

Angular のコンポーネントで使用するために、まずは NgModule で GridsterModule クラスをインポートします。

HTML (app.component.html)

<button type="button" (click)="addItem()">タイル追加</button>

<gridster [options]="options">
  <gridster-item [item]="item" *ngFor="let item of items; let index = index">
    <div class="draggable-handler">
      Header
    </div>
    <div>
      Content
    </div>
    <div>
      <button type="button" (click)="removeItem(index)">削除</button>
    <div>
  </gridster-item>
</gridster>
Element Property: Type Description
gridster option: GridsterConfig 各種設定やコールバック関数を指定
gridster-item item: GridsterItem タイルの位置やサイズを指定

gridster タグを配置し、 option プロパティへ GridsterConfig 型のデータをバインドします。

gridster の Style には width: 100%;height: 100%; が指定されているので、配置先の親要素と同サイズまで広がります。

gridster タグ内部の gridster-item タグが一つのタイルに相当し、 item プロパティへ GridsterItem 型のデータをバインドすることでタイルの位置やサイズを設定します。

Component (app.component.ts)

...
import { GridsterConfig, GridsterItem } from 'angular-gridster2';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  options: GridsterConfig = {};
  items: Array<GridsterItem> = [];

  ngOnInit(): void {
    this.options = {
      draggable: {
        enabled: true,
        ignoreContent: true,
        dragHandleClass: 'draggable-handler',
      },
      resizable: {
        enabled: true,
      },
      swap: true,
    };

    this.items = [
      { x: 0, y: 0, rows: 1, cols: 1 },
      { x: 0, y: 1, rows: 1, cols: 1 },
    ];
  }

  /** タイル追加 */
  addItem(): void {
    this.items.push({ x: 1, y: 0, rows: 1, cols: 1 });
  }

  /** タイル削除 */
  removeItem(index: number): void {
    this.items.splice(index, 1);
  }
}

gridster コンポーネントoption プロパティにバインドする GridsterConfig データと、 gridster-item コンポーネントitem プロパティにバインドする GridsterItem データを定義します。

また、タイル (gridster-item コンポーネント) の追加や削除も、このサンプルコードのように動的に行うことができます。

今回はサンプルのため固定位置にタイルを追加していますが、追加するタイルの位置とサイズには、本来配置したい任意の位置とサイズを指定してください。

リファレンス

主要そうなプロパティをリファレンスとしてまとめました。

各項目の説明は僕の独断と偏見に満ちた超訳になりますので、正確な内容は GitHub の公式リポジトリ公式 Demo サイト などの一次ソースをご確認ください。

また、こちらで紹介するプロパティは一部だけなので、さらに多くのプロパティを知りたい場合は、同じく公式 (ry

そして、今回は時間の都合上、イベントとコールバック関数については取り上げていないので、こちらについても (ry

GridsterConfig

Property Description Type Default
gridType Grid 内部の幅と高さの設定方法。 'fit' はスクロールバーが表示されないように Grid 内部の幅と高さの中で調整される。 String 'fit'
compactType Grid 内の Item の自動整列方法 (上寄せや左寄せなど) 。 'none' は自動整列無し。 String 'none'
displayGrid Grid 内の境界線の表示方法。 'onDrag&Resize' はドラッグ中やリサイズ中のみ、境界線を表示する。 String 'onDrag&Resize'
margin Grid 外枠と内部の Item の余白。 Grid の padding と同義。 Number 10
outerMargin Grid 外枠の内部の Item の余白有無。 Boolean true
outerMarginTop Grid 外枠と内部の Item の上部余白。 margin の値より優先される。 Grid の padding-top と同義。 Number null
outerMarginRight Grid 外枠と内部の Item の右部余白。 margin の値より優先される。 Grid の padding-right と同義。 Number null
outerMarginBottom Grid 外枠と内部の Item の下部余白。 margin の値より優先される。 Grid の padding-bottom と同義。 Number null
outerMarginLeft Grid 外枠と内部の Item の左部余白。 margin の値より優先される。 Grid の padding-left と同義。 Number null
fixedColWidth gridTypefixed を指定した場合に適用される、一列あたりの固定幅。 Number 250
fixedRowHeight gridTypefixed を指定した場合に適用される、一行あたりの固定高さ。 Number 250
minCols Grid の最小列数。 Number 1
maxCols Grid の最大列数。 Number 100
minRows Grid の最小行数。 Number 1
maxRows Grid の最大行数。 Number 100
defaultItemCols Grid 内の Item の横方向の規定サイズ。最小値は 1 。 Item の cols が省略された場合に使用される。 Number 1
defaultItemRows Grid 内の Item の縦方向の規定サイズ。最小値は 1 。 Item の rows が省略された場合に使用される。 Number 1
swap Grid 内の Item を移動する際、移動先に別の Item が存在した場合の制御。 true を指定すると、移動先の Item と位置の入れ替えを行う。 Boolean true
pushItems Grid 内の Item を移動・リサイズする際、移動・リサイズ先に別の Item が存在した場合の制御。 true を指定すると、移動先の Item を移動させる。 Boolean false
disablePushOnDrag Grid 内の Item を移動する際、移動先に別の Item が存在した場合の制御。 true を指定すると、移動先の Item を移動しない。 pushItems より優先される。 Boolean false
disablePushOnResize Grid 内の Item をリサイズする際、リサイズ先に別の Item が存在した場合の制御。 true を指定すると、リサイズ先の Item を移動しない。 pushItems より優先される。 Boolean false
pushResizeItems Grid 内の Item をリサイズする際、リサイズ先に別の Item が存在した場合の制御。 true を指定すると、リサイズ先の Item のサイズを縮小する。 pushItems と併用した場合、先に移動先の Item が可能な限り縮小された後に移動させる。 Boolean false
draggable Grid 内の Item のドラッグ制御方法。 Draggable -
resizable Grid 内の Item のリサイズ制御方法。 Resizable -

GridsterConfig.Draggable

Property Description Type Default
enabled Grid 内の Item のドラッグ可否。 true を指定すると Item がドラッグ可能になる。 Boolean false
ignoreContent Grid 内の Item 全域のドラッグ可否。 true を指定すると、 dragHandleClass で指定したクラスを持つ要素以外のドラッグが不可になる。 Boolean false
dragHandleClass ignoreContenttrue にした場合、ここで指定したクラスを持つ要素のみがドラッグ可能要素となる。ドラッグの可否は enabled の値に準ずる。 String ‘drag-handler’

GridsterConfig.Resizable

Property Description Type Default
enabled Grid 内の Item のリサイズ可否。 true を指定すると Item がリサイズ可能になる。 Boolean false

GridsterItem

Property Description Type Default
x Item の横方向の表示開始位置。 0 始まり。省略時、または既に Item が存在する場合は、自動的に空き位置に配置される。 Number undefined
y Item の縦方向の表示開始位置。 0 始まり。省略時、または既に Item が存在する場合は、自動的に空き位置に配置される。 Number undefined
cols Item の横方向のサイズ。最小値は 1 。省略時は GridsterConfig.defaultItemCols の値が使用される。 Number undefined
rows Item の縦方向のサイズ。最小値は 1 。省略時は GridsterConfig.defaultItemRows の値が使用される。 Number undefined
dragEnabled Item のドラッグ可否。 GridsterConfig.Draggable.enabled を Item 毎に上書きしたい場合に使用する。 Boolean undefined
resizeEnabled Item のリサイズ可否。 GridsterConfig.Resizable.enabled を Item 毎に上書きしたい場合に使用する。 Boolean undefined

おわりに

今まで OSS や商用ソフトウェアを含む様々なパッケージやライブラリを使用してきましたが、日本語の公式ドキュメントや多くの日本語ブログなどに、知らず知らずのうちに助けられてきたのだなと改めて痛感させられました。

自分の力だけでやってきたと思い込んできたものも、先人たちの偉大な教えや知恵の上で回っていたに過ぎなかったのです…

そして、これもまた過去何度も思ったことではありますが、やっぱり英語ができるエンジニアは有利だなと思いました。

日本語のドキュメントが無いだけで一気に作業効率がガタ落ちしますし、大体どこの (公式を含む) ドキュメントを見ても一次ソースは英語であることがほとんどです。

やっぱり、少しずつ英語の勉強もしないといかんな… _(-ω-`_)⌒)_

【Cloud】大手クラウドサービスの IaaS 運用コストを比較してみた

Cloud

はじめに

有名どころのクラウドサービスの IaaS の運用コストを調べる機会があったので、費用面から見た各社の特徴をまとめてみました。

ちなみに、僕は開発でクラウドサービスを利用したことはあるものの、導入や構築などの経験は一切ありませんので、完全なる素人が調べた内容になっています。

間違っているところがあれば、コメントで指摘頂けると助かります (´ε`; )

良い意味で浅い内容に仕上がっていると思うので、これからクラウドサービスを利用したいと考えている方には丁度良い取っ掛かりになるかもしれません。

また、タイトルには "運用コストを比較" と書いていますが、利用する規模や頻度等によって金額が大きく異なるため、具体的な金額等は一切書いていません。

一通り各社の料金形態について把握したら、それぞれの公式サイトにある料金計算ツールを使用して金額を見積もってみましょう。 (丸投げ)

比較対象

今回の比較対象となる各社の IaaS はこちら。

すべて 2021 年 6 月現在のデータでの比較となります。

え?それ IaaS なの?というつっこみは受け付けません。

クラウドサービスの運用コスト

Amazon Web Service (AWS) - Amazon Elastic Compute Cloud (Amazon EC2)

AWS の料金については、こちらに詳しく記載されています。

aws.amazon.com

以降は上記の公式ページからの引用と、僕の超訳まとめになります。

従量制料金

aws.amazon.com

Amazon EC2 は使用した分だけ課金される従量制料金となっています。

必要に応じてスケールすることが容易なため柔軟で無駄の無い運用を行うことができますが、例えば Amazon EC2 を利用して定額制のサービスを展開する場合、使用時間やトラフィックを見誤った料金設定を行うと赤字になる可能性があるため注意が必要です。

Amazon EC2 の主な支払いのプランは以下の通りです。

オンデマンド

aws.amazon.com

契約期間の縛りなどは無く、使用するインスタンス (Amazon EC2 上で稼働する仮想サーバ) の稼働時間に応じた料金を後払いします。

必要な規模の仮想サーバを必要なときに調達でき、料金も使用した分を後払いするため、無駄なコストや手間を省くことが可能です。

ただし、特に割引等は無いため、予め一定期間以上使用することが決まっていたり、必要なキャパシティが一定などの場合は、後述する割引有のプランがお勧めです。

スポットインスタンス

aws.amazon.com

ざっくり言うと、 AWS 上の余った Amazon EC2 領域を格安で利用できるプランです。

Amazon EC2 の余り領域が無くなればインスタンスは中断されてしまうことになるので、停止しても問題が無い用途のインスタンスに限るか、その他のプランのインスタンスと組合せて使用することになります。

利用料金は需給状況によってリアルタイムに変化しますが、割引率は大きく設定されており、上手く運用できればオンデマンドの最大 90% OFF で Amazon EC2 を使用することができるため、運用コストの大幅な削減に繋がります。

リザーブインスタンス (RI)

aws.amazon.com

予め指定したインスタンスを 1 年または 3 年といった期間で契約し、そのインスタンスを使用する場合に限り、オンデマンドの料金から最大 75% OFF で利用することができます。

また、オンデマンドやスポットインスタンスと違い、料金を前払いすることで更に割引率を高めることも可能です。

デメリットとしては、契約期間中は使用しなくても料金が発生することになるため、必ず一定のコストがかかることになります。

一定のスペックで定常的な仮想サーバの稼働が見込まれる場合はオンデマンドと比較してメリットがありますが、稼働状況に波がある場合は結果的にオンデマンドよりも高額になってしまう可能性があります。

Savings Plans

aws.amazon.com

リザーブインスタンスが特定のインスタンスを一定期間使用するという契約なのに対し、 Savings Plans はインスタンス全体の一定期間の特定の使用量を契約するようなイメージです。

ちょっと分かりづらいですが、 1 年または 3 年の期間でどのくらい使用するかを前もって契約しておくことで、オンデマンドで使用した場合と比較して最大 72 % OFF の割引を受けることができます。

リザーブインスタンスと違い、インスタンスを指定する必要が無く、 Amazon EC2インスタンス全体に対して割引が適用されるため、柔軟性のあるプランになっています。

デメリットは…うーん、特に無いように感じます。。

Microsoft Azure - Azure Virtual Machines

Microsoft Azure の料金についてはこちら。

azure.microsoft.com

以降は AWS と同様、公式ページからの引用と僕の超訳まとめです。

従量制料金

azure.microsoft.com

Azure Virtual Machines も Amazon EC2 と同様に、従量課金制の料金形態となっています。

割引についても Amazon EC2 と概ね同様ですが、 Microsoft Azure には Windows Server や SQL Server といった Microsoft 製品を使用する場合に適用される割引があるなど、 Microsoft ならではの強みが存在します。

Azure ハイブリッド特典 (Azure Hybrid Benefit)

azure.microsoft.com

もし既に Windows Server や SQL Server などのライセンス、またはサブスクリプション契約を有している場合、それを Azure Virtual Machines へ適用することができます。

この特典を後述する Azure Reserved VM instances などと組み合わせれば、通常の従量料金と比較して最大 85% OFF のコスト削減が可能になります。

オンプレミスの Windows Server からの移行や余っているライセンスがある場合は、他のクラウドサービスと比べて資源を有効活用できるため、現在 Microsoft 製品を主に使用しているなら Microsoft Azure を選択するメリットは大きくなります。

これこそ Microsoft ならではと言えますね。

Azure Spot Virtual Machines

azure.microsoft.com

これは Amazon EC2 のスポットインスタンスとほぼ同様のプランになります。

Amazon EC2 の場合は停止の 2 分前に通知が来ますが、こちらは 30 秒前の通知なので若干猶予が少ないです。

詳細は割愛します。 (決して該当の公式ページが翻訳されていなかったからではない)

Azure Reserved VM Instances

azure.microsoft.com

こちらも Amazon EC2リザーブインスタンスとほぼ同様のプランですが、支払いは全額一括前払いか毎月の分割前払いになります。 (Amazon EC2 は前払い無しも選択できます)

また、 Amazon EC2 との違いの一つとして、契約時に決めていた利用期間やインスタンスの変更、途中解約による一部返金など、後からでも契約内容を変更することが可能という点が挙げられます。

Google Cloud - Compute Engine

Google Cloud の料金についてはこちら。

cloud.google.com

以降は AWSMicrosoft Azure 同様、公式ページからの引用と僕の超訳まとめになります。

従量制料金

cloud.google.com

Google Cloud の Compute Engine も、前述の 2 社と同様、従量課金制となっています。

後述する割引については Amazon EC2Microsoft Azure と比べて若干少なく感じますが、今回詳細まで調べてはいないものの、そもそもの通常料金が他社よりも安いとの情報がインターネット上で散見されました。

単純に同程度のインスタンスを使用したケースで比較すると Google Cloud の方が安いようなので、後述する割引を組み合わせれば、もしかしたら一番運用コストを安く抑えることができるのかもしれません。 (もちろん使用状況によると思います)

確定利用割引

cloud.google.com

これまで見てきた Amazon EC2リザーブインスタンスMicrosoft Azure の Azure Reserved VM Instances と同様に、 1 年または 3 年間の利用契約をすることで、最大 57% OFF の割引を受けることができます。

途中でインスタンスのスペックを変更しても割引が適用されるので、稼働状況に合わせて柔軟にスケールすることが可能です。

継続利用割引

cloud.google.com

他社を含めたこれまでの割引と違い、こちらはインスタンスの実行時間が一定の割合を超過した際に自動で適用されるものになります。

この割引を適用させるための設定等は不要のため、つまりはたくさん使えば勝手に安くなってくれる長期優良割引みたいなものです。

ただし、前述の確定利用割引との併用はできないという点には注意が必要です。

おわりに

2021 年 6 月現在、様々なクラウドサービスが展開されているなとは思っていましたが、各社の料金形態だけでも非常に複雑なルールやプランが存在するということが分かりました。

さらに、今回取り上げた 3 社はそれぞれ数十から数百のクラウドサービスを展開しており、ちょっと調べた程度ではその全貌を知ることは不可能に近いです…

この他に Oracle Cloud や Alibaba Cloud といった他社クラウドサービスもそれぞれ独自のプランや強みを持っていて、これらの中から最適なクラウドサービスを見付けるのは至難の業です。

ただ、逆に考えればこれらすべてとは言わないまでも、いくつかのクラウドサービスに精通した知識や経験を有することは他のエンジニアとの差別化にも繋がり、より自分自身の市場価値の向上に寄与するなとも思いました。

これまであまりクラウドサービスを使用する機会は多くありませんでしたが、時代に取り残されないように、今後はもっとプライベートでも積極的にクラウドサービスを使っていきたいと思います。

なんてことを 2021 年の今頃言っているようでは、もうずいぶん出遅れてしまっているんでしょうけれど ( っ・∀・)≡⊃ ゚∀゚)・∵.

【脱IE】Internet Explorer のサポート終了が与えるレガシーな社内 Web システムへの影響と対策

Internet Explorer

はじめに

先日、 Microsoft から Internet Explorer デスクトップアプリ (以下「IE」と称する) のサポート終了が発表され、一部の Windows OS のバージョンを除き、 2022 年 6 月 15 日 (水) をもって IE はその長い歴史に幕を閉じることになりました。

blogs.windows.com

IE のサポート終了の流れは既に数年前から始まっていて、主要な Windows OS においては 2016 年 1 月に IE11 以外のバージョンのサポートを終了しており、それから 5 年以上の年月を経て、ようやくの IE 終了に歓喜する Web エンジニアも少なくないと思います。

直近 5 年間の国内外の Web ブラウザシェアの推移を見ると、 IE の全体に占める割合は一桁台で減少の一途を辿っており、人によって見方は変わると思いますが、モダンブラウザへの移行は概ね順調であると言えます。

gs.statcounter.com

しかし、この話題でよく問題になるのは、 IE 独自の機能拡張 *1 に依存した処理が至る所に実装された、昔から存在する企業内の業務用社内 Web システムです。

Web エンジニアにはお馴染みですが、 IEMicrosoft によって独自の機能拡張が施されており、 Web 標準に準拠していない IE でしか使用できない機能が存在します。

これらが多用されたレガシーな Web システムをモダンブラウザに対応させるための工数は少なくなく、特に社内向け Web システムは利益に直結しないケースも多いことから、開発が先送りされてきたのが現状だと思います。

ということで今回は、レガシーな社内 Web システムでよく使用されている IE 独自の主だった機能拡張 *2 とその代替手段、そして IE からモダンブラウザへの移行時に合わせて検討した方がいいと思われることを独断と偏見でまとめてみました。

モダンブラウザでは使用できない IE 独自の機能

IE 独自の機能拡張については、 Windows Blog に Windows 10 の標準ブラウザである Microsoft Edge でサポートされない IE の機能や API がまとめられており、 Microsoft Edge でサポートされない ≒ Web 標準でない ≒ IE 独自の機能拡張 と理解しても、大きく間違ってはいないと思います。

blogs.windows.com

これらの中から私の経験を踏まえて、おそらく多くの現場で使われているであろう技術とその代替手段を取り上げていきます。 (完全に独断と偏見です)

ActiveX

ActiveXMicrosoft が開発したインターネット関連技術群の総称で、初っ端からですが、もしかしたらこれが一番厄介かもしれない機能です。

IEJavaScript エンジンである Chakra (jscript9.dll) では、細かいことをすっ飛ばすと、 ActiveXObject を使用することで Windows 上のファイル操作やコマンドが実行できるという、今となってはとんでもない機能が用意されています。

もちろん、これを使用するためには IE の設定でセキュリティレベルを下げるなどの明示的な対応が必要なため、一般的には安全だと思われるイントラネット内での社内 Web システムだからこその機能であると言えます。

よくある例

var fso = new ActiveXObject('Scripting.FileSystemObject');

fso.DeleteFile('ファイルパス', true); // 悪用厳禁

代替手段

ActiveXObject を使用すればある程度何でもできてしまうので社内向け Web システムでは意外と多く使用されてきたと思いますが、当然セキュリティはガバガバになるわけで、モダンブラウザにおいてはこんな操作ができるわけがなく、 Web 標準や ECMAScript にもこれに代わる機能は存在しません。

モダンブラウザでサポートされる WebAssembly でも、将来的にどうなるかは分かりませんが、現時点ではセキュリティ上の制約からローカルファイルへのアクセスは難しそうです。

基本的には設計を見直すか、何かしらのファイルをダウンロードしてローカル PC 上で手動で実行してもらうなどの方法を取らざるを得ないため、確実に仕様を変える必要が出てきます。

一番厄介と書いた理由は、これを決裁権を持つ偉い人に説明して納得してもらうのが難しい可能性があるからです…

これを説明しなければならない担当者の方には、大変ですねとしか言えません…

VBScript (Web クライアントスクリプト処理)

VBScript には、 IE で実行される Web クライアントスクリプト処理と Internet Information Service (IIS) で実行される Web サーバスクリプト処理 (Acrive Server Pages (ASP)) があり、今回対象となるのは IE で実行される Web クライアントスクリプト処理になります。

IIS で実行される Web サーバスクリプト処理はブラウザには依存しないため、 IE のサポート終了による影響を受けません。 (IIS 10.0 のサポート終了日は 2027 年となっているので、まだまだ VBScript 自体は健在のようです…)

Windows Blog で言及されていますが、既に IE11 では VBScript の実行が非推奨となっており、既定の設定では VBScript は実行されません。

blogs.windows.com

ただし、後述する Document mode による互換表示設定を行うことで VBScript の実行が可能になるため、 VBScript を使用している社内 Web システムでは、 IE の設定や HTML の meta 要素などで互換表示設定を行っているケースが多いと思います。

よくある例

<script language="VBScript">
MsgBox(
  "モダンブラウザへ移行してよろしいですか?", 
  vbOkCancel + vbQuestion, 
  "モダンブラウザ移行"
)
</script>

代替手段

VBScript に関しては、基本的には JavaScript への書き換えが可能です。

VBScript の組み込み関数のすべてが JavaScript の標準組み込みオブジェクトでカバーできるわけではありませんし、もちろん VBScript で書かれたコードを解析して JavaScript に書き換えるという手間は発生しますが、大きな問題にはならないはずです。

"基本的に" と書いたのは、 VBScript の組み込み関数で用意されている CreateObject 関数が問題で、これを使用すれば COM オブジェクト (ActiveX オブジェクト) への参照が取得でき、前述の ActiveX で書いたこととと同様のことができてしまいます。

Dim Fso

Set Fso = CreateObject("Scripting.FileSystemObject")

Fso.DeleteFile("ファイルパス") ' やっぱり消せちゃう

やはりこれに対しても前述した通り、設計を見直すなどの対応が必要となり、偉い人へ説明する担当者の方は (ry

Document modes (互換表示)

Web 標準は W3C (World Wide Web Consortium) 、 JavaScript の規格である ECMAScriptECMA International のもとでそれぞれ標準化が進められており、その時々のニーズに沿った新しい仕様・規格が活発に議論されています。

各モダンブラウザは基本的にこれらの標準化された仕様に準拠するよう実装され、新機能の先行実装や非推奨になった機能の削除など、比較的頻繁にアップデートが行われています。

IE もバージョンが上がる度に徐々に Web 標準への移行が進み、最終バージョンである IE11 では比較的モダンブラウザに近いレンダリングや動作をしますが、 IE8 やそれ以前のバージョンはかなり癖があると言っても過言ではありません。

こうした癖のある古い Web ページや Web システムを動作させるため、 MicrosoftIE後方互換性を維持するために実装した機能が Document modes です。

Document modes が使えなくなるということは、前述した二つ (ActiveXVBScript)) も含め、 IE の過去バージョンでのエミュレート (互換表示) ができなくなることを意味するため、モダンブラウザへ移行するためには Web 標準や ECMAScript に準拠したコードへの修正が必要になります。

よくある例

<!-- Document modes でエミュレートするバージョンを指定 -->
<meta http-equiv="X-UA-Compatible" content="IE=5">
<script>
  // attachEvent() は IE8 以前でしか動かない
  // showModalDialog() は多くのモダンブラウザで廃止済み
  document.getElementById('button')
    .attachEvent('onclick', function () {
      window.showModalDialog('modal.html');
    });
</script>
<frameset cols="30%, *">
  <frame src="side_menu.html" name="side_menu">
  <frame src="main.html"> name="main">
  <noframes>
    現在ご利用のブラウザは frameset に対応していません。
  </noframes>
</frameset>

代替手段

Web 標準の HTML / CSS を書こう!
そして、 ECMAScript に準拠した JavaScript を書こう!

これに尽きます。

とは言っても、先にも述べた通り社内 Web システムではなるべく工数を抑えたいという事情があるので、 JavaScript については attachEventshowModalDialog といったキーワードで検索して必要な箇所のみ修正を行い、レイアウト (HTML / CSS) については非常に面倒ではありますが、実際にモダンブラウザで表示させながら修正を加えていくしかないのかなと思います。

もちろん、 frameset などの分かりやすいものであれば、キーワードで検索して修正するのも一つの方法です。

特に古い quirks mode については Microsoft Docs で確認することができますが、これを一つ一つ検索して対応するのは至難の業です…

docs.microsoft.com

こうした対応をするにあたって、ここであえて社内 Web システムの良いところを挙げるならば、エンドユーザが社内の人であることが多いので、多少の不具合は何とかなるということでしょうか。

ただし、これもまた担当者の立場が外注や派遣だったりすると (ry

モダンブラウザ移行時に対応したいこと

ここからは、 IE からモダンブラウザへ移行する際、合わせて検討してもいいと思うことを挙げていきます。

ちなみに、どうせモダンブラウザへ移行するなら、 Angular や Vue.js で SPA 化したら?というのは無しの方向でお願いします。

あくまでも基本的な路線はなるべく工数をかけずに、でも、どうせやるなら一緒に対応できることは合わせてやってしまいたいという目線で考えてみました。

jQuery

IE を使用する社内 Web システムでは、 jQuery を使用しているケースが多いと思います。 (hrgm 調べ)

jQuery は 2021 年 6 月現在で 3.6.0 が最新バージョンとなっていますが、 IE で使用できる jQuery のバージョンは大きく二つに分類されます。

IE jQuery
~ 8 1.n
9 ~ 2.n, 3.n

IE8 と IE9 の間を境にして、 IE8 以前はバージョン 1.nIE9 以降はバージョン 2.n3.njQuery が使用可能で、 jQuery のバージョンが上がれば使用できるメソッドなどに若干の違いが出ますが、バージョンアップにより軽量化やパフォーマンス向上の恩恵が受けられます。

また、各モダンブラウザについては、基本的に最新版とその一つ前のバージョンへの対応が明記されています。

jquery.com

もしモダンブラウザへの移行を考えているのであれば、合わせて jQuery の最新化も検討してみてはいかがでしょうか。

ただし、 jQuery のバージョンアップには少ないながらもいくつか破壊的な変更が含まれており、元々非推奨だったメソッドの削除などが行われているため、移行には多少注意が必要です。

jQuery 公式から提供されている移行用ライブラリを使用するか、もしくは社内 Web システム内で使用している jQuery の機能には一定の傾向があると思うので、例えば load メソッドなど多用している場合はキーワード検索で修正箇所を特定するなど、ピンポイントの対応でもいいかもしれません。

github.com

Bootstrap

Bootstrap も比較的使用されていることが多いと思いますが、つい最近 Bootstrap 5 がリリースされ、このバージョンから jQuery が不要になるなどの大きな変化がありました。

Bootstrap も jQuery と同じく、せっかくモダンブラウザへ移行するならバージョンアップを検討してもいいと思いますし、もし将来的に IE だけでなく jQuery からの脱却も視野に入れているならば、このタイミングで Bootstrap 5 へ移行してしまうのもアリかと思います。

かなり端折った Bootstrap の各バージョンとブラウザへの対応状況は以下の通りですが、 Bootstrap はバージョンが変わるとデザインや書き方も多少変わるため、 jQuery と同じくコードの修正やターゲットブラウザでの確認が必要になります。

Bootstrap jQuery Browser
3 要 (※) IE8 ~, 各モダンブラウザ
4 要 (※) IE10 ~, 各モダンブラウザ
5 不要 IE 非対応, 各モダンブラウザ

※ Bootstrap で用意されている Components を使用しない場合、 jQuery は必須ではない。

Bootstrap 3 のサポートは既に終了していますが、 Bootstrap 4 以降は基本的に jQuery と同様に各モダンブラウザの最新版とその一つ前のバージョンがサポートされます。

Bootstrap のマイグレーションについては公式ドキュメントにも記載があるので、これを見ながら対応すれば大丈夫だと思います。 (簡単だとは言ってない)

getbootstrap.jp

getbootstrap.jp

その他のライブラリについて

jQuery や Bootstrap といった有名なライブラリだけでなく、中にはあまり知られていないライブラリを使用していることもあると思います。

これらは既に開発が止まってしまっているケースも多く、今まで述べてきたような IE に依存する実装が内部でなされている場合は、別のライブラリへ切り替えるか自前で実装を行わなければいけません。

運良く開発が続いていてモダンブラウザへの対応がされていたり、何もしなくてもそのままモダンブラウザで動けばラッキーくらいに考えておき、基本的には対応が必要になると思っていた方が無難かもしれません。

社内 Web システムでは外部のライブラリを使用するために許可が必要だったりするので、あまり無いことだとは思いますが、過去または現在の担当者が勝手にライブラリを入れていたりすると、なかなか面倒なことになったりします…

IE を使い続けることはできないか

Microsoft による IE のサポートは終了しますが、アプリ自体が使えなくなるわけではないはずなので、おそらく継続して IE を使用することはできると思います。

ただし、サポートが終了するということはセキュリティアップデートも当然行われないため、特に企業内での既定ブラウザとして IE を使い続けることはお勧めできません。

それではモダンブラウザへの移行に伴い、これまで使用してきた社内 Web システムを必ず改修しなければいけないかと聞かれたら、そういうわけでもありません。

Microsoft EdgeInternet Explorer モード

ここまで色々書きましたが、 IE の後継ブラウザである Microsoft Edge には IE モードが搭載されており、実はこの機能を使用すれば、これまで取り上げた ActiveX コントロールや Document mode などをそのまま使用することができます。

docs.microsoft.com

もちろん、この IE モードにもサポート期限は存在しますが、現時点においては少なくとも 2029 年までのサポートが明言されています。

docs.microsoft.com

これはつまり、 2022 年 6 月に IE のアプリとしてのサポートは終了するものの、使用する Web ブラウザを Microsoft Edge へ移行してしまえば、さらにあと 7 ~ 8 年は今まで同様にレガシーな Web システムが利用可能ということを意味します。

各企業の方針にもよるとは思いますが、基本的に機能追加などを改修をほとんど行わない場合は Microsoft Edge への移行のみを行い、 Web システム自体には手を加えずに IE モードのサポート期限ギリギリまで粘るということも不可能ではありません。

しかし、機能追加や改修を頻繁に行うような Web システムになると、対応を先送りすればするほど IE モードのサポート終了まで技術的な負債を積み上げることになるので、やはりどこかのタイミングで Web 標準への対応を行った方が、長い目で見れば工数が少なくて済むという見方もできます。

この辺りは社内 Web システムの開発頻度や使用状況、モダンブラウザ対応を行うにあたってかけられる工数や費用によって変わってくるので、担当部門や各ステークホルダーと要相談になるかと思います。

おわりに

現在のブラウザシェアでは一桁台となりましたが、 IE はこれまで長きに渡り Web ブラウザのデファクトスタンダードの地位を守ってきました。

それ故にバージョンアップやサポート終了による影響力は甚大で、ここまでずっと Microsoft によって後方互換性が維持されてきたのも頷けます。

IE のサポートが終了すると言っても、前述した通り Microsoft Edge では引続き IE モードによって既存の Web サイトや Web システムを使用することができるため、一番取り残されているであろう社内 Web システムの Web 標準への対応はまだ先になるかと思います。

ただ、アプリとしての IE が無くなり、社内の既定ブラウザが Microsoft Edge を含むモダンブラウザへ移行することには大きな意味があると考えます。

それは、もし今後新規で Web システムを構築する場合、何の気兼ねもなく最新の Web 関連技術を使用することができるからです。

今はまだ涙をこらえて秀丸でコードを書いて IE を手動でリロードしながら開発をしていても (数年前の僕です) 、 Visual Studio Code でコードを書いて CLI でタスクランナーを走らせながらブラウザをライブリロードするなんて未来がやってくるかもしれません! (適当)

でもこれ、偉い人が理解して許可してくれるかどうかは…おっと、長くなったので今日はここまで。

それでは、社内 Web システム開発に関わるすべての Web エンジニアに幸多からんことを (*˘人˘*)

*1:紛らわしいが、アドオン (拡張機能) ではない。

*2:しつこいようですが、アドオン (拡張機能) ではない。

【Python】pyenv で複数バージョンを管理する (チートシート付)【Ubuntu】

python-logo

はじめに

サードパーティ製のパッケージだけでなく、プログラミング言語自体も日々のアップデートによって頻繁にバージョンアップが行われており、継続的なアプリ開発を行っていく上では、アプリ毎に使用する言語やパッケージのバージョンを管理する必要が出てきます。

最近、 WSL 2 を使用して UbuntuPython の開発環境を構築した際に、複数の Python のバージョンを管理するために pyenv を導入したので、インストール方法と使い方についてまとめてみました。

おまけとして、主に使用する pyenv コマンドをチートシートとして合わせてまとめています。

動作環境

OS Version
Ubuntu 20.04 LTS

Windows 10 Pro の Windows Subsystem for Linux (WSL 2) を使用

Application Version
Git 2.25.1
pyenv 1.2.21

pyenv のインストール

pyenv のソースコードGitHub から clone して .bashrc へ必要な情報を追記するだけで、 pyenv のインストールは完了します。

詳細は GitHub の pyenv 公式の README.md に書いてあるので、こちらを見た方が間違いないです。

github.com

以下は pyenv 公式のインストール手順を参考に、実際に Ubuntu の環境へインストールした手順になります。

1. pyenv のソースコードを clone する

git clone https://github.com/pyenv/pyenv.git ~/.pyenv

ユーザのホームディレクトリ直下に、 GitHubリポジトリから pyenv のソースコードを clone します。

2. 環境変数を定義する

echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc

環境変数 PYENV_ROOT へ先程 clone した .pyenv ディレクトリのパスを定義し、次に環境変数 PATH.pyenv/bin を追加する処理を、ユーザのホームディレクトリ直下にある .bashrc へ追記します。

3. pyenv 初期化処理を .bashrc へ追記する

echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n  eval "$(pyenv init -)"\nfi' >> ~/.bashrc

pyenv init - では、 pyenv に必要な環境変数の定義や初期化処理が実行されます。

実際の処理の内容は、 echo "$(pyenv init -)" で確認できます。

4. Bash (シェル) を再起動する

exec "$SHELL"

.bashrc に必要な処理をすべて書いているので、 source ~/.bashrc でも大丈夫のような気がしますが、 pyenv 公式のインストール手順には上記スクリプトが書いてあるので、素直に Bash を再起動します。

正確には、新たなシェルを起動して自分自身と置き換える、でしょうか?

これで pyenv のインストールは完了です。

pyenv の使い方

pyenv コマンドを使用して、 Python のインストールや python コマンドで実行される Python のバージョンの設定を行います。

Python のインストール

# Python のバージョン 3.9.0 をインストール
pyenv install 3.9.0

インストールしたい Python のバージョンを指定して、 pyenv install コマンドを実行します。

pyenv でインストール可能な Python のバージョンは、 pyenv install --list で確認することができます。

【エラー発生時】Ubuntu に不足するパッケージを追加

pyenv で Python をインストールする際、パッケージが不足していると Python のビルドでエラーが発生するか、インストールに成功しても一部のモジュールが使用できない場合があります。

今回使用した環境は WSL 2 上のまっさらな Ubuntu 20.04 LTS ですが、 pyenv のみインストールして Python 3.9.0 をインストールしたところ、ビルドエラーが発生しました。

pyenv の Python のインストールログは、 /tmp/ ディレクトリに python-build.yyyymmddhh24miss.fff.log というファイル名で出力されます。

GitHubpyenv 公式 Wiki に OS 毎の推奨ビルド環境が記載されているので、こちらを参考に必要なパッケージを追加しましょう。

github.com

僕の環境 (Ubuntu 20.04 LTS) では、以下のパッケージを追加することで、正常に Python をインストールできるようになりました。

sudo apt update
sudo apt upgrade
sudo apt install build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev tk-dev libffi-dev liblzma-dev libgdbm-dev libdb-dev
Packages Description
build-essential gcc や make などのビルドパッケージ群
libssl-dev Python 標準モジュールの依存パッケージ
zlib1g-dev Python 標準モジュールの依存パッケージ
libbz2-dev Python 標準モジュールの依存パッケージ
libreadline-dev Python 標準モジュールの依存パッケージ
libsqlite3-dev Python 標準モジュールの依存パッケージ
tk-dev Python 標準モジュールの依存パッケージ
libffi-dev Python 標準モジュールの依存パッケージ
liblzma-dev Python 標準モジュールの依存パッケージ
libgdbm-dev Python 標準モジュールの依存パッケージ
libdb-dev Python 標準モジュールの依存パッケージ

Python のインストールは、正常に完了するまで何度でもリトライすることが可能です。

使用する Python のバージョン切替

# 現在のシェル固有の Python のバージョンを 3.9.0 に設定
pyenv shell 3.9.0

# カレントディレクトリ以下で固有の Python のバージョンを 3.9.0 に設定
pyenv local 3.9.0

# すべてのシェルで使用される Python のバージョンを 3.9.0 に設定
pyenv global 3.9.0

使用するコマンドにより、設定する Python のバージョンの有効範囲が変わります。

複数の設定が存在する場合の優先順位は shell > local > global となります。

現在設定されている Python のバージョンは、 pyenv version コマンドで確認できます。

Python のアンインストール

# Python のバージョン 3.9.0 をアンインストール
pyenv uninstall 3.9.0

不要になった Python のバージョンは、 pyenv uninstall コマンドでアンインストールできます。

venv との組み合わせ

pyenv は Python 自体のバージョンを管理するものですが、これと合わせて Python 標準ライブラリの venv を利用することで、設定した Python のバージョンでパッケージを管理する仮想環境を作成することができます。

# Python のバージョンを設定
pyenv shell 3.9.0

# カレントディレクトリに仮想環境を作成
python -m venv --upgrade-deps venv

# 仮想環境を有効化
source venv/bin/activate

この例では pyenv shell コマンドを使用して現在のシェル固有の Python のバージョンを設定していますが、次回からは pyenv での Python の設定内容にかかわらず、仮想環境を有効化するだけで仮想環境作成時に設定したバージョンの Python が使用できます。

pyenv コマンドチートシート

Command Description
pyenv install --list pyenv でインストール可能な Python のバージョンを一覧表示
pyenv install [version] 指定したバージョンの Python をインストール
pyenv versions pyenv でインストールした Python を一覧表示
pyenv shell [version] 現在のシェルで使用する Python のバージョンを設定
pyenv local [version] カレントディレクトリ以下で使用する Python のバージョンを設定
pyenv global [version] すべてのシェルで使用する Python のバージョンを設定
pyenv version 現在設定されている Python のバージョンを表示
pyenv uninstall [version] 指定したバージョンの Python をアンインストール

※ その他のコマンドや詳細は GitHub の pyenv 公式 Command Reference を参照

github.com

おわりに

pyenv を使用すれば一つの OS 上で複数の Python のバージョンを管理することができますが、アプリ開発環境という視点で見れば PythonPython パッケージのバージョンだけでなく、 Web サーバや DBMS などのミドルウェアのバージョンも管理する必要があります。

最近は WSL 2 によって Windows ユーザにも Docker が身近になりつつあるので、 今後は Web サーバや DBMS などのミドルウェアも合わせてコンテナ化し、一つのアプリ開発環境として管理するのが主流になるかもしれません。

とは言っても、手軽に Python のバージョン管理を行う際はやはり pyenv が有用なので、要件に合わせて使い分けするのがベターではないでしょうか。

ちなみに僕は今 Docker に興味津々なので、ある程度使えるようになったら、次は Docker のまとめエントリを書きたいと思っています (o´艸`)