default eye-catch image.

Snowpark Container Services上でWebアプリ(FastAPI/React/TypeScript)を動かしてみた

シンプルな Multi-Container App を動かしている以下の記事にインスパイアされてみました。 以下の記事では、Docker networkを前提にフロントがサーバの名前解決を行っています。 これをデプロイすると、ブラウザで動くフロントコードがサーバの名前を解決できません(SPCS無関係)。 リバースプロキシを挟んでプライベートなダウンストリームにAPIを配置する方法が良さそうです。 今回の記事はSPCSの動作確認をすることが目的なので凝ったことはせず、 ViteをそのままデプロイしてProxyで解決してみたのでご紹介します。 [clink implicit=\"false\" url=\"https://medium.com/@maseedilyas9848/snowflake-container-mastery-step-by-step-deployment-of-your-multi-container-app-with-snowpark-211682514851\" imgurl=\"https://miro.medium.com/v2/resize:fit:1400/format:webp/1*t7s-Rl6F4BBV-yYs-ovODQ.png\" title=\"Snowflake Container Mastery: Step-by-Step Deployment of Your Multi-Container App with Snowpark Container Services\" excerpt=\"The buzz around town is all about Snowflake’s latest product feature, “Snowpark Container Services” and the excitement is real. Now, with the feature hitting public preview in various AWS regions, this blog dives into the nitty-gritty of what container services bring to the table. Join me as we explore what makes this feature tick and unravel the steps to deploy a multi-container app within Snowflake. Let’s break it down!\"] [arst_toc tag=\"h4\"] SPCSのアーキテクチャ Image Registryはイメージリポジトリです。AWSのECR、AzureのACRと似た感じで操作できます。 Container Serviceはデプロイメントの単位で、1個以上のコンテナをデプロイできます。 Compute Poolは計算資源で、複数のContainer Serviceが共有します。 Serviceは基本的にはPrivateなリソースとなりますが、SpecでEndpointsを定義することで、 Publicリソースとすることができます。自動的に80にmapされます。 Serviceには以下のフォーマットでDNS名が付きます。 Service同士は以下のDNS使ってプライベート通信できます。 同一DB、Schema内に作成したServiceは先頭のServiceNameが異なるだけとなりますが、 その場合に限り、ServiceNameだけで互いの名前解決ができます。 Service間連携については、公式で\"Service-to-Service\"というパターンで紹介されています。 <Service Name>-<Schema Name>-<DB Name>.snowflakecomputing.internal 1つのService内に複数のコンテナを配置することができます。 同一Service内で各コンテナ内の通信したいと考えたのですが、方法を見つけることができませんでした。 (出来ないはずはなさそうで方法はあるのかもしれません..) 今回作るもの フロント側、サーバ側の2つのコンテナを、それぞれ別々のServiceとしてデプロイします。 フロント側をPublic、サーバ側はPrivateとします。概要は以下の通りです。 フロント側 Vite React/TypeScript ReactからのAPIリクエストは一旦ViteのProxyで受けて、ProxyからAPIに流す サーバ側にGETリクエストして応答を表示するだけ サーバ側 uvicorn FastAPI poetry GETリクエストを受けて\"Hello World\"をJSONで返すだけ 思いっきり開発用な感じですが、SPCSの動作確認が目的ですのでこれでいきます。 ローカルで動作確認をして、SPCSにデプロイします。ファイル構成は以下の通りです。 $ tree . -I node_modules -I __pycache__ . ├── api │   ├── Dockerfile │   ├── api.py │   ├── app.py │   ├── main.py │   └── pyproject.toml ├── compose.yml └── front ├── Dockerfile ├── entry.sh ├── index.html ├── package-lock.json ├── package.json ├── src │   └── hello.tsx ├── tsconfig.json ├── tsconfig.node.json └── vite.config.ts compose.yml サーバ側、フロント側の2つのコンテナが、サーバ側->フロント側の順に起動するように書きます。 それぞれ、8080、5173 で待つようにします。 services: api: build: api volumes: - ./api:/app ports: - 8080:8080 front: build: front volumes: - ./front:/app ports: - 5173:5173 depends_on: - api サーバ側 Snowflakeの公式のチュートリアルだとFlaskが使われています。 今回は、最近使い始めたFastAPIを使ってAPIサーバを立ててみようと思います。 FlaskとFastAPIの比較はこちらが詳しいです。 FastAPIの特徴はPydanticによるデータ検証とAsyncI/O。TypeScriptのように型チェックできます。 パッケージマネージャにはpoetryを使います。デファクトが無いPythonのパッケージ管理界隈で npmやcomposer的な使い勝手が提供されます。 FastAPIの公式では、Python用Webサーバのuvicornを使ってホストされています。 uvicornでFastAPIを動かすコンテナを1個立てていきます。 Dockerfile 最新のPythonのイメージにpoetryをインストールします。 公式がインストーラを配布していて公式の手順通りに叩けばインストールできます。 公式のガイドの通り、POETRY_HOME=/etc/poetry とします。 Installation with the official installer FROM python:3.12 # 公式の通り /etc/poetry にインストールする ENV POETRY_HOME=/etc/poetry RUN curl -sSL https://install.python-poetry.org | python - ENV PATH $POETRY_HOME/bin:$PATH WORKDIR /app COPY . . RUN poetry install CMD [\"python\",\"main.py\"] pyproject.toml バニラのPythonとpyproject.tomlだけで依存関係を考慮したパッケージ管理が出来ますが、 要はnpmやbundle,composer的な使い勝手に寄せたパッケージ管理に対する需要があります。 poetry用の依存関係を書いていきます。fastapi、uvicornの現在(2/16)の最新を指定します。 [tool.poetry] name = \"test\" [tool.poetry.dependencies] python = \"^3.12\" fastapi = \"^0.109.2\" uvicorn = \"^0.27.1\" api.py [GET] /hello に対して Hello World 的な JSON を返す FastAPI の Hello Worldです。 後のapp.pyで FastAPIインスタンスに紐付けます。app.pyと分離することでロジックを分離できます。 from fastapi import APIRouter router = APIRouter() @router.get(\"/hello\") async def hoge(): return {\"result\":\"Hello World\"} app.py FastAPIのHello Worldコードです。Dockerfileから開始します。 from api import router as api_router from fastapi import FastAPI app = FastAPI() app.include_router(api_router, prefix=\"/api\") main.py pythonコードからuvicornを起動します。uvicorn.runの公式の仕様はこちら。 第1引数の\"app:app\"は\"app\"モジュールの中の\"app\"オブジェクトという表記です。 app.pyに記述したFastAPI()のインスタンスappを指します。stringで渡す必要があります。 hostは\"0.0.0.0\"を指定します。なぜ\"127.0.0.1\"でないのかはこちらが参考になります。 今回はPort=8080で起動します。reload=Trueとすると、HotReload機能が有効になります。便利。 import uvicorn if __name__ == \"__main__\": uvicorn.run( \"app:app\", host=\"0.0.0.0\", port=8080, reload=True, ) 起動してみる docker compose up して http://localhost:8080/docs を開くと以下が表示されます。 ちゃんとJSONでHello Worldが戻りました。 フロント側 VueとReactの開発用に使われるローカル開発用のサーバ Vite をホストするコンテナを立てます。 Viteは Vue.jsの開発者Evan You氏が開発したJavaScript/TypeScriptで、ヴィートと読み、 フランス語で\"素早い\"という意味だそう。(webpackのように)リソースバンドルが不要で起動が速い。 (Laravelも9.xでwebpackを捨ててViteになってた..) 素の状態でTypeScriptを扱えるため、すぐにTypeScriptを書き始められる特徴があります。 Dockerfile nodeのrelease scheduleはこちら。 2/17のnodeのActiveLTSのMajor Versionは20で、2026-04-30がEnd of lifeとなっています。 これを使いたいので node:20 を指定します。 FROM node:20 WORKDIR /app COPY . . RUN npm install ENTRYPOINT [ \"./entry.sh\" ] entry.sh Dockerfile の ENTRYPOINT で npm run dev するだけのshです。 #!/bin/bash npm run dev package.json npm create vite@latest で Prjディレクトリ内に様々なファイルが作られます。 package.jsonも作られます。 Hello World で必要なもの以外を削ってみました。 npm install後、npm run devで viteを実行します。 TS用のconfigは別です。 他に生成されるpackage-lock.jsonが必要ですが省略します。 { \"name\": \"front\", \"private\": true, \"version\": \"0.0.0\", \"scripts\": { \"dev\": \"vite\" }, \"dependencies\": { \"react\": \"^18.2.0\", \"react-dom\": \"^18.2.0\" }, \"devDependencies\": { \"@vitejs/plugin-react\": \"^4.2.1\" } } tsconfig.json viteのPrj生成で自動生成されるTS用のconfigファイルです。 手をつけずに配置します。 { \"compilerOptions\": { \"target\": \"ES2021\", \"useDefineForClassFields\": true, \"lib\": [\"ES2021\", \"DOM\", \"DOM.Iterable\"], \"module\": \"ESNext\", \"skipLibCheck\": true, /* Bundler mode */ \"moduleResolution\": \"bundler\", \"allowImportingTsExtensions\": true, \"resolveJsonModule\": true, \"isolatedModules\": true, \"noEmit\": true, \"jsx\": \"react-jsx\", /* Linting */ \"strict\": true, \"noUnusedLocals\": true, \"noUnusedParameters\": true, \"noFallthroughCasesInSwitch\": true }, \"include\": [\"src\"], \"references\": [{ \"path\": \"./tsconfig.node.json\" }] } tsconfig.node.json viteのPrj生成で自動生成されるTS用のconfigファイルです。 手をつけずに配置します。 { \"compilerOptions\": { \"composite\": true, \"skipLibCheck\": true, \"module\": \"ESNext\", \"moduleResolution\": \"bundler\", \"allowSyntheticDefaultImports\": true }, \"include\": [\"vite.config.ts\"] } vite.config.ts viteのPrj生成で自動生成されるvite用のconfigファイルです。 設定ファイルが.tsなところが凄いです。普通にimport文を書けます。 上のuvicornの起動で127.0.0.1ではなく0.0.0.0を指定したのと同様に、 viteも127.0.0.1ではなく0.0.0.0で待たせる必要があります。 serverオプションのhostにtrueを設定すると、0.0.0.0となります。公式 FastAPIの同一パスと対応するProxyを設定します。 以下で、server.proxy.api.target は SPCS上のAPIコンテナのPrivateエンドポイント を表します。 DNS名はサービス単位で作られます。本来長いFQDNを指定する必要がありますが、 同一スキーマに作られたサービスに限り、サービス名だけで解決できるようです。 DNS名はアンダースコア(_)がハイフン(-)に置き換わります。6時間くらいハマりました.. 後で ikuty_api_service サービスを作りますが、ikuty-api-serviceを 使います。 詳細は以下を参照してください。 Service-to-service communications import { defineConfig } from \'vite\' import react from \'@vitejs/plugin-react\' export default defineConfig({ plugins: [react()], server: { host: true, proxy: { \"/api\": { target: `http://ikuty-api-service:8080/`, changeOrigin: true } } }, }) index.html Reactのコンポーネントを表示するガワとなるhtmlです。 <!DOCTYPE html> <html> <head> <meta charset=\"UTF-8\" /> <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" /> <script type=\"module\" src=\"/src/hello.tsx\" defer></script> </head> <body> <div id=\"root\">Waiting...</div> </body> </html> src/hello.tsx ようやくHello WorldするReactコンポーネントの本体です。 画面にはvalueというStateを表示しています。APIのURLは上記の通りproxyとします。 今回作成した/api/hello APIの応答を受けた後、setValueによりStateを更新します。 import React from \'react\' import { useState } from \'react\' import ReactDOM from \'react-dom/client\' const App = () => { const [value, setValue] = useState(\'\') const url = \'/api/hello\' fetch(url,{}) .then(res=>res.json()) .then(data=>setValue(data[\'result\'])) return ( {value},{} ) } ReactDOM.createRoot(document.getElementById(\'root\')!).render( ) 起動してみる docker compose up すると、ほとんど一瞬でviteが起動します。 http://localhost:5173 を開きます。 Waiting...という表示が一瞬で Hello World に書き変わります。 ロールの作成 SPCSの各リソースの作成に必要な権限はこちらにあります。 ゴリ押ししただけなので間違っている可能性大です.. 行ったり来たりしたので足りないものがあるかもしれません。 use role ACCOUNTADMIN; CREATE ROLE IKUTY_CONTAINER_USER_ROLE; GRANT ROLE IKUTY_CONTAINER_USER_ROLE TO ROLE ACCOUNTADMIN; GRANT USAGE ON DATABASE IKUTY_DB TO ROLE IKUTY_CONTAINER_USER_ROLE; GRANT USAGE ON SCHEMA IKUTY_DB.PUBLIC TO ROLE IKUTY_CONTAINER_USER_ROLE; GRANT CREATE IMAGE REPOSITORY ON SCHEMA T_IKUTA_DB.PUBLIC TO ROLE IKUTY_CONTAINER_USER_ROLE; -- CREATE SERVICEに必要な権限 -- https://docs.snowflake.com/en/sql-reference/sql/create-service#access-control-requirements GRANT USAGE ON DATABASE IKUTY_DB TO ROLE IKUTY_CONTAINER_USER_ROLE; GRANT USAGE ON SCHEMA IKUTY_DB.PUBLIC TO ROLE IKUTY_CONTAINER_USER_ROLE; GRANT CREATE COMPUTE POOL ON ACCOUNT TO ROLE IKUTY_CONTAINER_USER_ROLE; GRANT CREATE IMAGE REPOSITORY ON SCHEMA IKUTY_DB.PUBLIC TO ROLE IKUTY_CONTAINER_USER_ROLE; GRANT CREATE SERVICE ON SCHEMA IKUTY_DB.PUBLIC TO ROLE IKUTY_CONTAINER_USER_ROLE; GRANT USAGE ON COMPUTE POOL IKUTY_SCS_POOL TO ROLE IKUTY_CONTAINER_USER_ROLE; GRANT BIND SERVICE ENDPOINT ON ACCOUNT TO ROLE IKUTY_CONTAINER_USER_ROLE; GRANT IMPORTED PRIVILEGES ON DATABASE snowflake TO ROLE IKUTY_CONTAINER_USER_ROLE; -- GRANT READ ON STAGE IKUTY_SCS_STAGE TO ROLE IKUTY_CONTAINER_USER_ROLE; GRANT READ ON IMAGE REPOSITORY IKUTY_SCS_REPOSITORY TO ROLE IKUTY_CONTAINER_USER_ROLE; GRANT BIND SERVICE ENDPOINT ON ACCOUNT TO ROLE IKUTY_CONTAINER_USER_ROLE; Image Repositoryの作成 SPCSで使用するイメージを配置するリポジトリを作成します。 AWSのECR、AzureのACR的に、dockerコマンドから透過的にpushできるようです。 公式は以下。 CREATE IMAGE REPOSITORY USE ROLE IKUTY_CONTAINER_USER_ROLE; CREATE OR REPLACE IMAGE REPOSITORY IKUTY_SCS_REPOSITORY; SHOW IMAGE REPOSITORIES; SHOW IMAGEを叩くと repository_url が返ってます。 Image Repositoryにプッシュする 作成したImage Repositoryにローカルで作成したイメージをpushしていきます。 pushは指定されたタグを送信するという仕様のため、docker tagコマンドでイメージにタグを付けます。 docker tagの仕様はこちら。 ローカルで以下を行います。(サニタイズのため分かりづらいですが補完してください..) # タグをつける # docker tag $ docker tag app_front:latest /app_front:scs $ docker tag app_api:latest /app_api:scs # Snowflake Image Repositoryにログインする $ docker login -u Login Succeeded # イメージをpushする $ docker push /app_front:scs ... $ docker push /app_api:scs ... Compute Poolを作成する Compute Poolを作成します。 CREATE COMPUTE POOL CREATE COMPUTE POOL ikuty_scs_pool MIN_NODES = 1 MAX_NODES = 1 INSTANCE_FAMILY = CPU_X64_XS AUTO_RESUME = TRUE INITIALLY_SUSPENDED = FALSE AUTO_SUSPEND_SECS = 3600 ; 以下でCREATEしたCompute poolをDESCRIBEできます。 DESCRIBE COMPUTE POOL 自分の環境だと、CREATE COMPUTE POOLしてから15分ほどステータスがSTARTINGでした。 15分ぐらいして叩くとステータスがACTIVEに変わりました。(結構かかるイメージ) 以下、公式の実行例です。 DESCRIBE ikuty_scs_pool +-----------------------+--------+-----------+-----------+-----------------+--------------+----------+-------------------+-------------+--------------+------------+-------------------------------+-------------------------------+-------------------------------+--------------+---------+ | name | state | min_nodes | max_nodes | instance_family | num_services | num_jobs | auto_suspend_secs | auto_resume | active_nodes | idle_nodes | created_on | resumed_on | updated_on | owner | comment | |-----------------------+--------+-----------+-----------+-----------------+--------------+----------+-------------------+-------------+--------------+------------+-------------------------------+-------------------------------+-------------------------------+--------------+---------| | IKUTY_SCS_POOL | ACTIVE | 1 | 1 | CPU_X64_XS | 1 | 0 | 0 | false | 1 | 0 | 2023-05-01 11:42:20.323 -0700 | 2023-05-01 11:42:20.326 -0700 | 2023-08-27 17:35:52.761 -0700 | ACCOUNTADMIN | NULL | +-----------------------+--------+-----------+-----------+-----------------+--------------+----------+-------------------+-------------+--------------+------------+-------------------------------+-------------------------------+-------------------------------+--------------+---------+ Serviceの作成 フロント側、サーバ側の2つのServiceを作成していきます。 specについて、ステージにファイルを配置してそれを指定するスタイルのほかに、 以下のようにCREATE SERVICEに含めるスタイルがあるようです。 CREATE SERVICE フロント側のServiceは以下です。 CREATE SERVICE ikuty_api_service IN COMPUTE POOL ikuty_scs_pool FROM SPECIFICATION $$ spec: containers: - name: api-container image: endpoints: - name: api port: 8080 $$ ; サーバ側のServiceは以下です。 CREATE SERVICE ikuty_front_service IN COMPUTE POOL ikuty_scs_pool FROM SPECIFICATION $$ spec: containers: - name: front-container image: endpoints: - name: front port: 5173 public: true $$ ; SERVICE用のシステム関数 SaaSで動くコンテナの動作を確認するのは結構面倒なことなのかなと思います。 自分の操作に対してSaaS側で何が行われているのか知りたいことは結構あるのかなと思います。 SPCSには以下のコマンドがあるようです。 SYSTEM$GET_SERVICE_STATUS SYSTEM$GET_SERVICE_LOGS エンドポイントURLの取得 SHOW ENDPOINTS すると、Specで指定したpublicなendpointを得られました。 ingress_url に なんとかかんとか.snowflakecomputing.app というURLが入っています。 SHOW ENDPOINTS 動作確認 Computing poolのStatusがACTIVEになってから、エンドポイントURLをブラウザで開くと、 期待通り、Reactで作ったHello Worldアプリが表示されます。 SYSEM$GET_SERVICE_LOGS()でフロントサービスのログを覗くと、viteの起動ログが出ていました。 そうえいば 5173 を 80 に mapping する記述をどこにもしていないのですが、そうなっています。 > front@0.0.0 dev > vite VITE v4.5.2 ready in 314 ms ➜ Local: http://localhost:5173/ ➜ Network: http://10.244.1.3:5173/ ➜ Network: http://172.16.0.6:5173/ 同様に、サーバ側のログを覗くと、uvicornの起動ログが出ていました。 ViteのProxyから8080で繋がるので、こちらは8080が開いています。 INFO: Will watch for changes in these directories: [\'/app\'] INFO: Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit) INFO: Started reloader process [1] using StatReload INFO: Started server process [8] INFO: Waiting for application startup. INFO: Application startup complete. まとめ SnowflakeをWebサーバのインフラにするだけの内容で正直意味がないです。 しかし、APIでSnowflakeに触ったり、Reactで格好良い可視化をしたり、夢は広がります。 FastAPI,React,TypeScriptの恩恵ゼロなので、今後ちょっと凝ったものを作ってみます。

default eye-catch image.

(今さら)Docker composeでWordPress環境を用意する

Hello World. docker-composeを使ってコンテナ間の繋がりを定義してみるデモに超速で入門する。 ゼロから書くと不要な時間を要するので、こちらを参考にさせていただいた。 写経する中でポイントを咀嚼していく。 ~/dockercompose_test というディレクトリを作成し、 その中で作業する。 docker-compose.yml 構成を記述する設定ファイル。ymlで書く。 ansibleでymlには慣れているので嬉しい。 version: \"3\" services: db: image: mysql:5.7 #container_name: \"mysql57\" volumes: - ./db/mysql:/var/lib/mysql restart: always environment: MYSQL_ROOT_PASSWORD: root_pass_fB3uWvTS MYSQL_DATABASE: wordpress_db MYSQL_USER: user MYSQL_PASSWORD: user_pass_Ck6uTvrQ wordpress: image: wordpress:latest #container_name: \"wordpress\" volumes: - ./wordpress/html:/var/www/html - ./php/php.ini:/usr/local/etc/php/conf.d/php.ini restart: always depends_on: - db ports: - 8080:80 environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_NAME: wordpress_db WORDPRESS_DB_USER: user WORDPRESS_DB_PASSWORD: user_pass_Ck6uTvrQ ルートはservices. 名称の理解がフワフワだが、コンテナをサービスと読んでいることが多いくらいの認識. 配下に db と wordpress が存在する。おなじみの構成を定義している。 db dbの定義についてパラメタを追っていく. パラメタ 値 説明 image mysql57 pull してくるイメージを書く. mysql57という名前のイメージをpullする. volumes - ./db/mysql:/var/lib/mysql コンテナ内の/var/lib/mysql を ホストの./db/mysql にマウントする(で良いか?) restart always 再起動ポリシー(コンテナ終了時に再起動するための仕組み)を設定する.再起動ポリシーを設定しておくことで、Dockerデーモンの起動時やホストOSの起動時に自動的にコンテナを開始できる。 alwaysの他にいくつかあるか今はスキップ. environment MYSQL_ROOT_PASSWORD: root_pass_fB3uWvTSMYSQL_DATABASE: wordpress_dbMYSQL_USER: userMYSQL_PASSWORD: user_pass_Ck6uTvrQ コンテナの環境変数を定義する. 環境変数名はコンテナ依存. wordpress wordpressの定義についてパラメタを追っていく. パラメタ 値 定義 image wordpress:latest pull してくるイメージを書く. wordpressという名前のイメージをpullする. バージョンは最新. volumes ./wordpress/html:/var/www/html./php/php.ini:/usr/local/etc/php/conf.d/php.ini コンテナ内のディレクトリをホストのディレクトリにマウントする.マウント先を定義する. restart always 再起動ポリシーをalwaysに設定.内容はdbと同じ. depends_on - db サービスの依存関係を定義する.要は起動する順番を定義する. wordpressのdepends_onにdbを設定することで,wordpressよりも先にdbを起動できる.dbの起動が完了するまで待ってくれるという意味ではない! Control startup and shutdown order in Compose. ports 8080:80 コンテナの80番をホストの8080にマップする. http://localhost:8080 とかするとコンテナの80番が開く. environment WORDPRESS_DB_HOST: db:3306WORDPRESS_DB_NAME: wordpress_dbWORDPRESS_DB_USER: userWORDPRESS_DB_PASSWORD: user_pass_Ck6uTvrQ wordpressコンテナの環境変数を設定する.環境変数はコンテナ依存. docker compose up 以下で定義したdocker-compose.ymlに基づいて構築が始まる. -dはDetachedMode. これによりバックグラウンドで実行される. $ docker-compose up -d ホストで http://localhost:8080 を開くと以下の通り. 永続化の確認 言語を設定しwordpressのインストールを完了させる. db(MySQL)に加えられた変更はホストにマウントされたファイルに反映される. 以下により環境を停止した後, 再度upしたとしても, ホストにマウントされたファイルへの変更が反映され, インストール済みの状態で立ち上がる. $ docker-compose down $ docker-compose up -d まとめ docker-compose を使った WordPress環境構築のデモに超速で入門した. 一緒にコンテナを永続化するデモにも入門した.

default eye-catch image.

(今さら)DockerでWordPress環境を用意する

最小の手数でHello world. とりあえず最小の手数でwordpressを起動してみる。 イメージのダウンロード docker pullでMySQLとWordPressのイメージをダウンロードする。 イメージはサービス単位。 \"MySQL\"を実現するためのOSとミドルウェア。 \"WordPress\"を実現するためのOSとミドルウェア。例えばWebサーバも含んでいる。 まずはMySQL。 $ docker pull mysql:5.7.21 5.7.21: Pulling from library/mysql 2a72cbf407d6: Pull complete 38680a9b47a8: Pull complete 4c732aa0eb1b: Pull complete c5317a34eddd: Pull complete f92be680366c: Pull complete e8ecd8bec5ab: Pull complete 2a650284a6a8: Pull complete 5b5108d08c6d: Pull complete beaff1261757: Pull complete c1a55c6375b5: Pull complete 8181cde51c65: Pull complete Digest: sha256:691c55aabb3c4e3b89b953dd2f022f7ea845e5443954767d321d5f5fa394e28c Status: Downloaded newer image for mysql:5.7.21 docker.io/library/mysql:5.7.21 次にWordPress。何も指定しないと最新が落ちる様子。 $ docker pull wordpress Using default tag: latest latest: Pulling from library/wordpress bb79b6b2107f: Pull complete 80f7a64e4b25: Pull complete da391f3e81f0: Pull complete 8199ae3052e1: Pull complete 284fd0f314b2: Pull complete f38db365cd8a: Pull complete 1416a501db13: Pull complete be0026dad8d5: Pull complete 7bf43186e63e: Pull complete c0d672d8319a: Pull complete 645db540ba24: Pull complete 6f355b8da727: Pull complete aa00daebd81c: Pull complete 98996914108d: Pull complete 69e3e95397b4: Pull complete 5698325d4d72: Pull complete b604b3777675: Pull complete 57c814ef71bc: Pull complete ed1877bc3d14: Pull complete 673ead1d3971: Pull complete Digest: sha256:46fc3c784d5c4fdaa46977debb83261d29e932289a68739f1e34be6b27e04f87 Status: Downloaded newer image for wordpress:latest docker.io/library/wordpress:latest MySQLコンテナを起動 コンテナ(イメージ)を起動する。 $ docker run --name test-mysql -e MYSQL_ROOT_PASSWORD=test-pw -d mysql 013a2eb6b5b1c0b0f61e85cace6540ec036be80c9f85e8c9b5ed3e114a4cc8e8 パラメタは以下の通り。 Option Value 説明 --name test-mysql コンテナに名前を付ける。この例であれば test-mysql -e MYSQL_ROOT_PASSWORD=test-pw コンテナの環境変数を設定する。MYSQL_ROOT_PASSWORDという環境変数としてtest-pwを設定 -d - DetachedMode(Background)を指定する。指定がない場合Foregroud. WordPressコンテナを起動 WordPressコンテナを起動する。 $ docker run --name test-wordpress --link test-mysql:mysql -d -p 8080:80 wordpress a1301075d3667de7eddd9edc0c46edaeb4346a5c46ef444538c9cf9987f31471 パラメタは以下の通り。 Option Value 説明 --link test-mysql:mysql コンテナを連携させる。書式は --link [コンテナ名]:[エイリアス]。test-mysqlがコンテナ名(前述)で、mysqlがそのエイリアス。 -p 8080:80 HostとGuestのポートマッピング。Hostの8080をGuestの80にマッピングする。 Hostの8080にWordPressコンテナ内の80がマップされた。 http://localhost:8080/ でWordPressの言語選択画面が表示される。 非同期で起動したコンテナにアタッチ docker execで非同期に起動したWordPressコンテナ内のディレクトリにアクセスできる。 この例だと/var/www/html。 ゴニョゴニョいじると変更が反映される。 $ docker exec -it test-wordpress /bin/bash root@a1301075d366:/var/www/html# もちろん、コンテナを落とすと変更は失われる。 まとめ DockerでWordPressを動かすデモに超速で入門した。

default eye-catch image.

MacでDockerお砂場を作る

docker on vagrant Docker for Macが遅いので,Webのコード書くのはvagrant+ansibleで済ませていたのだけれども, vagrant上にdockerを立てることでLinux上で走らせるのと同レベルの速度を得られるようなので, docker on vagrantを立ててdockerに入門してみる。 Web開発していない人から見ると,なんでdocker使わないの? ってことなのだが, 気持ちは以下の通り. 工夫無しだと1度試したら2度とやりたくないレベルで使い物にならない. Docker For Macが遅い:対策の実験 Macのdockerが遅いストレスから解放されよう ansibleで自動化してたから手間に気づかなかったけど, 公式がイメージ配ってるんだから,手間なしなのはdocker. 本番環境と開発環境を揃えにくいかなとも思うけど, AWS ECS的なものもあって,そもそもdockerだけで完結する世界が主流になりそうな感. docker on vagrantで遅さを回避できるので, 言い訳してないでアップデートしていく.. なぜ遅いのか Docker for Macは, AlpineLinuxベースのHyperkitVMの上で透過的にContainerを扱う. Mac上でDockerコマンドを実行すると,透過的にHyperkitVM上に反映される. Macの上で直接Containerが動いているのではなくこのVMの上でContainerを動かしている. HostとGuestのファイルシステムをマウントする観点ではvagrantも同じで, 実際,VagrantfileでマウントオプションとしてNFSを指定したとしてもNativeよりかなり遅い. ファイルシステムの対称性がある分,vagrantはHostとGuestをSyncする方法に手を入れやすく, HostとGuestのファイルシステムをNativeと同等レベルの速度でSyncする手段を導入できる. この仕組みによると, vagrantの上でDockerを動かすパフォーマンスがNative並に速くなる. Mutagen HostとGuestのファイルシステムをSyncするためにMutagenを利用する. Overviewによると,Mutagenは双方向の同期ツールで,低レイテンシをうたっている. もともとHostToGuestというよりはLocalToCloudの統合を目指している感じ. キーボードを打ってから反映されるまでのラグが気になる, とかOSが違う場合のアレコレ(permissionとかシンボリックリンックとか),とか, そういうところの解消を目指している様子. エージェントレス,TCP,でリモートへの導入コストが少ないのが良い. VagrantにはMutagen over SSHの形を取る. インストール手順 こちらが参考になりました。わかりやすく,手順通りやれば10分かかりません. Vagrantを使う「Mac最速のDocker環境」を初心者向けに解説【遅いMac for Dockerを卒業】 とりあえず箱だけ作った.Laravelだと分かりづらいのでRailsで試したところ激しく速かった. 副次的な効果として、Macを汚さないのでお砂場にぴったり.

default eye-catch image.

vagrant userがdockerに入門するためのチートシート

vagrantを知っていてこれからdockerに入門する方向のチートシートを書く。 dockerコンテナの方が小さいので基本的に粒度が合わないが、 対称性を重視して似た機能を並べてみた。 コマンド一覧(vagrant list-commands)からメジャーなのをピックアップした。 Dockerコンテナのネットワーク設定等、概念違いで比較しづらいものは除いた。 また、各コマンドにはパラメタが必要だが煩雑になるため省略した。 vagrant box / docker image操作 vagrant docker boxの一覧vagrant up imageの一覧docker images boxの追加vagrant box add */*imageの追加docker pull imageの詳細docker inspect * boxの削除vagrant box remove *imageの削除docker rmi * boxの更新vagrant box update */*imageの更新docker pull * 全boxの更新vagrant box update imageからbox初期化vagrant init * imageのタグ設定docker tag * vagrant 仮想マシン操作/コンテナ生成/起動/停止 vagrant docker 仮想マシン起動vagrant upコンテナ生成/起動docker run コンテナバックグラウンド実行docker run -d コンテナ起動docker start 仮想マシン終了vagrant haltコンテナ停止docker stop 仮想マシン再起動vagrant reloadコンテナ再起動docker restart 仮想マシン一時停止vagrant pauseコンテナ中断docker pause 仮想マシン再開vagrant resumeコンテナ再開docker unpause 仮想マシン削除vagrant destroyコンテナ削除docker rm 仮想マシンステータス表示vagrant status 全マシン一覧vagrant global-status稼働コンテナ一覧docker ps -a 仮想マシンログインvagrant ssh スナップショット(vagrantのみ) vagrant スナップショット作成vagrant snapshot save * スナップショット復元vagrant snapshot restore * スナップショット削除vagrant snapshot delete * スナップショット一覧vagrant snapshot list dockerコンテナはホストと共有する範囲が大きく、全環境で完全に同じように動かすことは 難しいかもしれない。 vagrantとdockerは排他的な存在ではなく、vagrant上にdockerコンテナっていう構成もありえる。 Vagrantfile, Dockerfile関連は次回...