クラウド・コンピューティングにおけるコンテナとは何か?
2013年にDockerが登場して以来、コンテナは爆発的な人気を博している。コンテナによってソフトウェアのデプロイ、配布、管理、スケーリングが容易になるため、すでに多くの企業がワークフローにコンテナを組み込んでいる。
この記事では、クラウド・コンピューティングにおけるコンテナとは何かを説明する。コンテナを使用するメリット、使用例、仮想マシンとの比較、DockerとKubernetesについて説明します。最後に、Back4app ContainersにWebアプリケーションをコーディング、Docker化、デプロイする方法をお教えします!
Contents
コンテナの定義
コンテナとは、コード、ランタイム、ライブラリ、環境変数、設定ファイルなど、アプリケーションの実行に必要なすべてを含むスタンドアロンの実行可能パッケージのことだ。コンテナ化されたアプリケーションの素晴らしい点は、ローカルの開発環境からパブリック・クラウドまで、あらゆる場所で実行できることだ。コンテナはサイズが小さく、効率的で、効果的な分離が可能だ。
コンテナを使用するメリット
コンテナを使うことにはいくつかの利点がある。そのいくつかを見てみよう。
効率性
コンテナにはオペレーティング・システム・イメージが含まれないため、従来のサーバーやVMよりもシステム・リソースが少なくて済む。そのため、非常に効率的でサイズも小さく(通常はMB単位)、1台のサーバーで多くのアプリケーションを実行できる。
アプリケーションの分離
コンテナは、アプリケーションとその依存関係をホストシステムから分離する。同時に、OSカーネルやCPU、メモリ、ストレージ、ネットワークなどのシステムリソースを共有することができる。
携帯性
コンテナ化されたソフトウェアは、コンテナ・エンジンがインストールされたマシンであれば、実質的にどのマシンでも同じように実行し、同じように動作する。これにより、異なる環境間でのアプリのデプロイや移動が容易になり、「自分のマシンでは動作する」という問題が解消される。
責任の分離
コンテナは、開発者とIT運用チームの間でタスクと責任を分担することで、責任の分離を可能にする。開発者はアプリケーション・コードと依存関係の作成と保守を担当し、IT運用チームはコンテナと基盤となるインフラのデプロイと管理に集中する。
アプリケーション開発の迅速化
コンテナ化によって、ソフトウェアの開発、テスト、管理、配布が容易になる。コンテナはCI/CDシステムと簡単に統合でき、ソフトウェア開発と出荷プロセスを大幅に加速できる。
簡単なスケーリング
コンテナ化されたアプリケーションは、Kubernetesのようなオーケストレーション・プラットフォームと組み合わせることで、オンデマンドで容易に拡張できる。これにより、コストを最小限に抑えながら、高いワークロードに対応することができます。
コンテナの使用例
コンテナ技術は、IT運用チームだけでなく、開発者にとっても多くのユースケースを持っている。
コンテナ・ネイティブ開発
コンテナネイティブ開発は、コンテナを主要な構成要素として活用するソフトウェア開発アプローチである。コンテナネイティブ開発では、アプリケーションをコンテナとしてパッケージ化し、コンテナ化された環境で実行する。この開発アプローチでは、コンテナが提供するクールな特典をすべて利用できる。
継続的インテグレーションと継続的デリバリー(CI/CD)
CI/CDパイプラインでは、コンテナを使用してアプリケーションをパッケージ化し、自動テストを実行することで、一貫性のある反復可能な方法でアプリケーションをテストおよびデプロイすることができます。コンテナはCI/CDパイプラインの一部として簡単に作成、テスト、デプロイでき、エラーのリスクを低減し、ソフトウェア開発プロセスの全体的な効率を向上させる。
マイクロサービス
コンテナは、マイクロサービス・アーキテクチャに従ったアプリの開発に使用できる。コンテナを使えば、モノリシックなアプリを疎結合できめ細かいサービスの集まりに簡単に分割し、異なるコンテナで実行できる。
開発環境
コンテナは、開発チームが開発環境を素早くセットアップすることを容易にする。ホストOSやホストライブラリに関係なく、一貫した開発環境を提供する。
バッチプロセス
バッチプロセスは簡単にコンテナ化し、クラウドにデプロイできる。各タスクは個別のコンテナ・イメージとしてパッケージ化され、個別のコンテナ・インスタンスとして実行される。これにより、各タスクが独自の環境で実行され、他のタスクに干渉しないため、リソースを効率的に利用できる。
コンテナと仮想マシンの比較
コンテナと仮想マシンは、仮想化に対する2つの異なるアプローチだ。共通点もあるが、まったく異なるものだ。
仮想マシン(VM)は物理ハードウェアを抽象化したものだ。これにより、1台のサーバーを複数のサーバーにすることができる。VMはそれぞれ独自のオペレーティング・システムを持ち、通常はハイパーバイザーによって管理される。VMは、(同じサーバー上で)複数のアプリケーションを実行したり、モノリシックなアプリケーションを実行したり、高度な分離とセキュリティを必要とするアプリケーションを実行したりするのに適している。その欠点は、多くのスペースを占有しがちで、起動にかなり時間がかかることだ。
一方、コンテナはオペレーティング・システム・レベルで仮想化されている。コンテナは同じLinuxカーネルを共有するため占有スペースが小さく、より効率的で起動が速く、拡張性が高く、より多くのアプリケーションを扱うことができる。コンテナはコンテナ・エンジンによって管理される。VMとは対照的に、コンテナの主な用途は、移植性、軽量性、スケーラビリティを必要とするマイクロサービスやアプリケーションである。
コンテナとVMを組み合わせて両方のメリットを得ることも可能だ。
DockerとKubernetes
コンテナで作業するための最も人気のある2つのツールは、DockerとKubernetesだ。両者がどのように機能するのかを説明し、その違いを見ていこう。
DockerはLinuxベースのオープンソースプロジェクトで、軽量コンテナ内のアプリケーションのデプロイと管理を自動化するために使用される。これにより、コンテナ化されたアプリケーションをさまざまな環境で効率的に動作させることができる。最近では、DockerはLinuxマシンから大規模なクラウド・プロバイダーまで、ほとんどどこにでもある。
最も人気のあるDockerの代替は、Podman、LXD、containerdだ。
Kubernetes(K8s)は、コンテナ化されたアプリケーションのデプロイ、スケーリング、管理を自動化するためのオープンソースのコンテナ・オーケストレーション・システムだ。2014年のリリース以来、クラウド環境におけるコンテナ化アプリケーションのデプロイと運用のデファクトスタンダードとなっている。Kubernetesの利点には、スケーラビリティ、高可用性、自動運用、インフラの抽象化、ヘルスモニタリングなどがある。
その他のオーケストレーション・プラットフォームには次のようなものがある:AWS ECS、Nomad、Red Hat OpenShiftなどだ。
では、DockerとKubernetesの違いは何だろうか?簡単に言えば、Dockerはコンテナ内でアプリケーションをパッケージ化して配布することを可能にし、Kubernetesは複数のコンテナが互いに調和して動作することを容易にする。
コンテナベースのアーキテクチャを使用したアプリの開発
このチュートリアルでは、シンプルな REST API を作成し、Docker 化し、Back4app Containers にデプロイします。
Back4app Containersとは?
Back4app Containersは、クラウドインフラストラクチャ内のグローバルに分散されたコンテナ上にアプリケーションをデプロイし、スケーリングするための無料のオープンソースプラットフォームです。
DevOpsの心配をすることなく、ソフトウェアに集中し、より速く出荷することができます。このプラットフォームはGitHubと密接に統合されており、CI/CDシステムが組み込まれているため、数分でアプリを立ち上げて実行することができる!
なぜBack4app Containersを使うのですか?
- GitHubとうまく統合
- ダウンタイムなしのデプロイメント
- 簡単な操作と無料ティア
- 優れたカスタマーサポート
プロジェクト紹介
映画のウォッチリストとして機能するシンプルなREST APIを構築します。ウェブアプリでは、映画の追加や削除などの基本的なCRUD操作ができるようにする。APIを作るにはFlaskフレームワークを使う。最後に、プロジェクトをDocker化し、Back4app Containersへのデプロイがいかに簡単かをデモします。
前提条件
コードアプリ
以下のステップでは、Pythonがインストールされている必要があります。Pythonがまだインストールされていない場合は、ダウンロードしてください。
プロジェクトの初期化
まず、アプリ専用のディレクトリを作成し、そこに移動する:
$ mkdir flask-watchlist
$ cd flask-watchlist
次に、新しい仮想環境を作成し、有効化する:
$ python3 -m venv venv && source venv/bin/activate
フレームワークとしてFlaskを使うので、それをインストールしなければならない:
$ (venv) pip install Flask==2.2.2
以下の内容でapp.pyを作成します:
# app.py
from flask import Flask
app = Flask(__name__)
app.config['JSON_SORT_KEYS'] = False
@app.route('/')
def index_view():
return {
'detail': 'Hello world!'
}
このコードはFlaskを初期化し、メッセージを返すシンプルなエンドポイントを作成します。
でサーバーを実行する:
$ flask run
http://localhost:5000/、「Hello world!
」というメッセージが表示されるはずだ。
データベース
データベースにはSQLiteを使う。SQLite は組み込み型のサーバレスリレーショナルデータベース管理システムです。データベースでの作業を簡単にするために、Flask-SQLAlchemy— SQLAlchemy のサポートをアプリに追加する Flask の拡張機能 — をインストールします。
インストールするには
$ (venv) pip install Flask-SQLAlchemy==3.0.3
次に、app.pyの先頭に移動し、データベースを初期化するように変更します:
# app.py
db = SQLAlchemy()
app = Flask(__name__)
app.config['JSON_SORT_KEYS'] = False
app.config['SECRET_KEY'] = '5b3cd5b80eb8b217c20fb37074ff4a33'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///default.db"
db.init_app(app)
輸入のこともお忘れなく:
from flask_sqlalchemy import SQLAlchemy
次に、データベース・モデルを定義しよう。
シンプルな映画ウォッチリストアプリを作るので、必要なモデルは1つだけです。Movie
モデルを次のように定義します:
# app.py
class Movie(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(128), nullable=False)
release_date = db.Column(db.Date(), nullable=False)
is_watched = db.Column(db.Boolean, default=False)
watched_at = db.Column(db.DateTime, default=None, nullable=True)
def as_dict(self):
return {c.name: getattr(self, c.name) for c in self.__table__.columns}
def __repr__(self):
return '<Movie %r>' % self.title
データベースを初期化して投入するために、簡単な Python スクリプトを作成します。プロジェクトのルートに移動し、init_db.pyという名前の新しいファイルを以下の内容で作成します:
# init_db.py
from datetime import date
from app import db, app
from app import Movie
with app.app_context():
db.create_all()
if Movie.query.count() == 0:
movies = [
Movie(title='Fight Club', release_date=date(1999, 9, 15)),
Movie(title='The Matrix', release_date=date(1999, 3, 31)),
Movie(title='Donnie Darko', release_date=date(2001, 1, 19)),
Movie(title='Inception', release_date=date(2010, 7, 16)),
]
for movie in movies:
db.session.add(movie)
db.session.commit()
最後にしなければならないのは、スクリプトを実行することだ:
$ (venv) python init_db.py
これにより、データベース、データベース・テーブルが作成され、それらにデータが入力されます。データベースファイルはインスタンスフォルダに置かれます。
APIエンドポイント
我々のウェブ・アプリは以下のエンドポイントを持つ:
/ 基本
的なAPI情報を返す/api/は
映画のリストを返す。/api/create/は
新しい映画をウォッチリストに追加する。/api/
/ 特定の映画の詳細を返す/api/watch/
/ ムービーを見たことにする。
app.pyの一番下にエンドポイントを定義します:
# app.py
@app.route('/')
def index_view():
return {
'name': 'flask-watchlist',
'description': 'a simple app for tracking the movies you want to watch',
'version': 1.1,
}
@app.route('/api/')
def list_view():
json = [movie.as_dict() for movie in Movie.query.all()]
return jsonify(json)
@app.route('/api/<int:movie_id>/', methods=['GET', 'DELETE'])
def detail_view(movie_id):
movie = db.get_or_404(Movie, movie_id)
if request.method == 'DELETE':
db.session.delete(movie)
db.session.commit()
return {
'detail': 'Movie has been successfully deleted.'
}
else:
return movie.as_dict()
@app.route('/api/create/', methods=['POST'])
def create_view():
title = request.form.get('title')
release_date = request.form.get('release_date', type=float)
if title is None or release_date is None:
return {
'detail': 'Please provide the title and release_date.'
}, 400
movie = Movie(title=title, release_date=datetime.fromtimestamp(release_date))
db.session.add(movie)
db.session.commit()
return movie.as_dict()
@app.route('/api/watch/<int:movie_id>/')
def watch_view(movie_id):
movie = db.get_or_404(Movie, movie_id)
if movie.is_watched:
return {
'detail': 'Movie has already been watched.'
}, 400
movie.is_watched = True
movie.watched_at = datetime.now()
db.session.commit()
return movie.as_dict()
輸入車のこともお忘れなく:
from datetime import datetime
from flask import request, jsonify
これでアプリはほぼ完成だ。開発サーバーを動かしてみよう:
$ (venv) flask run
映画リストを取得できるかテストする:
$ (venv) curl http://localhost:5000/api/ | jq '.'
[
{
"id": 1,
"title": "Fight Club",
"release_date": "Wed, 15 Sep 1999 00:00:00 GMT",
"is_watched": false,
"watched_at": null
},
{
"id": 2,
"title": "The Matrix",
"release_date": "Wed, 31 Mar 1999 00:00:00 GMT",
"is_watched": false,
"watched_at": null
},
...
]
Gunicorn
Flaskの開発用サーバーは本番用には適していないので、Gunicornと交換してみよう。Gunicornまたは “Green Unicorn “は、本番環境に対応したUnix用のPython WSGI HTTPサーバーだ。
を実行してインストールする:
$ (venv) pip install gunicorn==20.1.0
パッケージがインストールされたら、次のようにWSGIサーバーを起動します:
$ (venv) gunicorn -w 2 -b 0.0.0.0:5000 app:app
[INFO] Starting gunicorn 20.1.0
[INFO] Listening at: http://0.0.0.0:5000 (1)
[INFO] Using worker: sync
[INFO] Booting worker with pid: 7
[INFO] Booting worker with pid: 8
このコマンドはUNIXベースのオペレーティング・システムでのみ動作することに留意してほしい。
これで2つのGunicornワーカーが起動し、アプリがインターネットに公開されます。アプリにアクセスするには、お気に入りのウェブブラウザを開き、http://localhost:5000。
要件.txt
アプリをDocker化する前にしなければならない最後のことは、requirements.txtファイルを作成することだ。requirements.txtファイルは、プロジェクトの依存関係を指定するために使用する。
それを生成する最も簡単な方法は、実行することである:
$ (venv) pip freeze > requirements.txt
Dockerizeアプリ
以下のステップでは、Dockerをインストールする必要があります。Dockerをインストールする最も簡単な方法は、Docker Desktopをダウンロードすることです。
Dockerがインストールされていることを確認するには、以下を実行する:
$ docker --version
Docker version 20.10.22, build 3a2c30b
Dockerfile
アプリケーションをDocker化するには、Dockerfileを使います。Dockerfileはプレーン・テキスト・ファイルで、ベース・イメージ、環境、環境変数、コマンド、ネットワーク設定、ボリュームなどを定義することができる。
プロジェクト・ルートに以下の内容でDockerfileを作成する:
# syntax=docker/dockerfile:1.4
FROM --platform=$BUILDPLATFORM python:3.10-alpine
# set the working directory
WORKDIR /app
# set environmental variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
# install the requirements
COPY requirements.txt /app
RUN --mount=type=cache,target=/root/.cache/pip \
pip3 install -r requirements.txt
# copy the code to the container
COPY . .
# initialize the database (create DB, tables, populate)
RUN python init_db.py
# expose
EXPOSE 5000/tcp
# entrypoint command
CMD ["gunicorn", "-w", "2", "-b", "0.0.0.0:5000", "app:app"]
- ベースイメージには
python:3.10-alpineを
使用。 PYTHONDONTWRITEBYTECODE を
1
に設定すると、Python は.pycファイルをディスクに書き込まなくなります。PYTHONUNBUFFEREDを
1に
設定することで、Pythonの出力ストリームがそのままターミナルに送られるようになります。
Dockerfileの書き方の詳細については、Dockerfileリファレンスを参照してください。
.dockerignore
Dockerはイメージをビルドする前に、.dockerignoreファイルを探します。.dockerignoreファイルによって、イメージに含めたくないファイルを定義できる。これにより、イメージのサイズを大幅に縮小することができます。.gitignoreファイルと同じような働きをします。
プロジェクトルートに、以下の内容の.dockerignoreファイルを作成する:
# .dockerignore
.git/
instance/
__pycache__/
.idea/
除外したいディレクトリやファイルがあれば追加してください。
イメージのビルドと実行
続いて、Dockerイメージをビルドしてタグ付けしてみよう。
$ docker build -t flask-watchlist:1.0 .
[+] Building 11.1s (15/15) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 32B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 34B 0.0s
=> resolve image config for docker.io/docker/dockerfile:1.4 0.5s
=> CACHED docker-image://docker.io/docker/dockerfile:1.4@sha256:9ba7531a0dbc 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> [internal] load .dockerignore 0.0s
=> [internal] load metadata for docker.io/library/python:3.10-alpine 0.5s
=> [stage-0 1/6] FROM docker.io/library/python:3.10-alpine@sha256:da5ab5e911253dfb 0.0s
=> [internal] load build context 0.3s
=> => transferring context: 182.45kB 0.2s
=> CACHED [stage-0 2/6] WORKDIR /app 0.0s
=> [stage-0 3/6] COPY requirements.txt /app 0.0s
=> [stage-0 4/6] RUN --mount=type=cache,target=/root/.cache/pip
pip3 install -r requirements.txt 7.2s
=> [stage-0 5/6] COPY . . 0.3s
=> [stage-0 6/6] RUN python init_db.py 1.5s
=> exporting to image 0.3s
=> => exporting layers 0.3s
=> => writing image sha256:2671ccb7546a0594807c721a0600a 0.0s
=> => naming to docker.io/library/flask-watchlist:1.0
画像をリストアップすると、新しい画像が表示されるはずだ:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
flask-watchlist 1.0 7bce66230eb1 8 hours ago 110MB
最後に、そのイメージを使って新しいDockerコンテナをスピンアップする:
$ docker run -it -p 5000:5000 flask-watchlist:1.0
[2023-02-02 20:08:57 +0000] [1] [INFO] Starting gunicorn 20.1.0
[2023-02-02 20:08:57 +0000] [1] [INFO] Listening at: http://0.0.0.0:5000 (1)
[2023-02-02 20:08:57 +0000] [1] [INFO] Using worker: sync
[2023-02-02 20:08:57 +0000] [7] [INFO] Booting worker with pid: 7
[2023-02-02 20:08:57 +0000] [8] [INFO] Booting worker with pid: 8
dを
使用すると、Dockerコンテナをデタッチモードで起動できる。つまり、コンテナはターミナルのバックグラウンドで実行され、入力を受け取ったり出力を表示したりしない。
これで、アプリがコンテナ内で実行されるようになった!http://localhost:5000にアクセスすると、以下のようなレスポンスが返ってくるはずだ:
{
"name": "flask-watchlist",
"description": "a simple app for tracking the movies you want to watch",
"version": 1
}
GitHub
アプリをBack4app Containersにデプロイするには、ソースコードをGitHubのリポジトリにアップロードする必要があります。GitHubに新しいリポジトリを作成し、リモートを追加し、.gitignoreを追加してコードをコミットします。コードをGitHubにアップロードしたら、次のステップに進みます。
アプリをBack4appコンテナにデプロイする
以下のステップでは、Back4appのアカウントが必要です。既にお持ちの場合はログインしてください。そうでない場合は無料アカウントにサインアップしてください。
Back4appを使うには、まずアプリを作成する必要があります。ダッシュボードにログインすると、アプリのリストが表示されます。新しいアプリを作成するには “Build a new app “をクリックしてください。
次に、”Containers as a Service “を選択する。
まだの場合は、GitHubをBack4appに接続し、デプロイしたいリポジトリをインポートしてください。GitHubが接続されると、リポジトリがテーブルに表示されます。
Select “をクリックして、デプロイしたいリポジトリを選びます。
次に、Back4appが環境設定を聞いてくる。アプリ名を決めてください。ここではflask-watchlistと
します。他はデフォルトのままで構わない。
最後に「Create App」をクリックすると、アプリが自動的に作成され、デプロイされる。
その後、アプリの詳細にリダイレクトされ、デプロイのログを見ることができます。
アプリがデプロイされるまで数分待ちましょう!アプリはBack4app Containers上で公開されました。アプリの動作を確認するには、左側に表示されている緑色のURLをクリックしてください。
結論
この記事を通して、コンテナとは何か、その利点について説明し、あなたのワークフローにコンテナを実装する方法を示しました。ここまでで、あなたは独自のシンプルなREST APIを構築し、それをドッカー化してBack4app Containersにデプロイできるようになったはずです。
GitHubリポジトリから最終的なソースコードを入手する。
今後のステップ
- データベースをイメージに保存すべきではありません。現時点では、再デプロイするたびにデータベースがリセットされてしまいます。マネージドPostgreSQLかMySQLインスタンスに切り替えることを検討してください。
- Dockerfileを最適化するためのマルチステージビルドについて学びましょう。
- ステップバイステップのチュートリアルについては、Dockerコンテナのデプロイの記事をお読みください。
よくあるご質問
コンテナとは何ですか?
コンテナとは、アプリケーションの実行に必要なすべて(コード、ランタイム、ライブラリ、環境変数、設定ファイル)を含むスタンドアロンの実行可能パッケージです。
コンテナを使用する利点は何ですか?
– 効率性
– アプリケーションの分離
– 責任の分離
– アプリケーション開発の高速化
コンテナと仮想マシンの違いは何ですか?
仮想マシン(VM)は物理ハードウェアの抽象化であり、コンテナはオペレーティングシステムレベルで仮想化されます。VMはより高度な分離とセキュリティを提供しますが、コンテナは容量が小さく、効率的でスケーラブルです。
DockerとKubernetesの違いは何ですか?
Dockerはアプリケーションをコンテナ内にパッケージ化して配布するためのツールであり、Kubernetesは複数のコンテナを連携して動作させるのを容易にします。
コンテナベースのアーキテクチャでアプリを開発するには?
1. プログラミング言語を選び、アプリを開発します。
2. DockerfileまたはDocker Composeを使ってアプリをDocker化します。
3. Dockerイメージを作成し、ローカルでテストします。
4. Back4app ContainersのようなCaaSを選び、コードをそこにプッシュします。
サービスのデプロイを待てば完了です!