Google Cloud Shell でDocker利用ハンズオン

はじめに

仕事の都合で GoogleCloudを触り始めた、GoogleCloud歴 4か月の駆け出しエンジニアです。

GoogleCloudのCloud Shell(AWSでもほぼ同機能のCloud Shellがあります)上で、コンテナを起動してデプロイしてみることに挑戦してみました。

構成概要図

  • Cloud Shellでコンテナ起動した際のイメージ図
    file

ハンズオン

今回は「四方に回転させたPDFを出力」する、アプリケーションを構築するものとします。

1.Google Cloudにてプロジェクト作成

  • 今回はハンズオンということもあり、オーナー権限にて構築を実施しております。

参照ブログ:AWS Lambda から Gemini APIを利用した呼出しハンズオン

2.PDF出力先のGCSバケットの作成

  • 「マネジメントコンソール」画面から「GCS」画面へ遷移します。
  • 「バケットを作成」を選択し、新規バケットを作成する。
設定内容
バケット名 ${バケット名} before-change-bucket

3.Cloud Shellの準備

3.1.事前準備

  • マネジメントコンソール右上 [>.] アイコンより、Cloud Shellの起動し以下コマンドを実施する。

  • Cloud Shellでディレクトリ作成

    mkdir ${フォルダ名}
    cd ${フォルダ名}
    touch app.py
    touch Dockerfile
    touch requirements.txt
    # 仮想環境を作成
    python3 -m venv venv
    # 仮想環境を有効化
    source venv/bin/activate

3.2.「app.py」について

3.2.1.処理フロー
項番 処理内容 出力ファイル
1 PDF作成 test.pdf
2 90°、180°、270°のPDF保存 rotated_0.pdf,rotated_90.pdf,rotated_180.pdf,rotated_270.pdf
3 4つのPDFをマージ merged_output.pdf
4 GCSアップロード gs://${2.PDF出力先のGCS}/merged_output.pdf
3.2.2.「app.py」コード

※生成AIにて構築

  • 74行目のgcs_bucket = "${PDF出力先のGCS名}"は、「2.PDF出力先のGCSの作成」で作成したバケット名を入力
import os
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from PyPDF2 import PdfReader, PdfWriter, PdfMerger
from google.cloud import storage

def create_test_pdf(filename):
    """ テスト用のPDFを作成 """
    c = canvas.Canvas(filename, pagesize=letter)
    c.drawString(100, 750, "This is a test PDF")
    c.drawString(100, 700, "Created for rotation testing")
    c.save()

def rotate_pdf(input_path, output_path, rotation):
    """ 指定した角度でPDFを回転 """
    reader = PdfReader(input_path)
    writer = PdfWriter()

    for page in reader.pages:
        page.rotate(rotation)
        writer.add_page(page)

    with open(output_path, "wb") as output_file:
        writer.write(output_file)

def merge_pdfs(output_filename, pdf_files):
    """ PDF をマージする """
    merger = PdfMerger()

    for pdf in pdf_files:
        print(f"Adding {pdf} to merged PDF")
        merger.append(pdf)

    merger.write(output_filename)
    merger.close()
    print(f"Successfully merged into {output_filename}")

def upload_to_gcs(bucket_name, source_file_name, destination_blob_name):
    """GCS バケットにファイルをアップロード"""
    storage_client = storage.Client()
    bucket = storage_client.bucket(bucket_name)
    blob = bucket.blob(destination_blob_name)

    blob.upload_from_filename(source_file_name)
    print(f"Uploaded {source_file_name} to gs://{bucket_name}/{destination_blob_name}")

def main():
    print("📌 回転したテスト用PDF作成 + マージ + GCSアップロード スクリプト")

    # テスト用PDFの作成
    test_pdf = "test.pdf"
    create_test_pdf(test_pdf)
    print(f"✅ テスト用PDFを作成しました: {test_pdf}")

    # 回転角度のリスト
    rotations = [0, 90, 180, 270]
    rotated_pdfs = []

    # 各回転角度でPDFを作成
    for rotation in rotations:
        output_file = f"rotated_{rotation}.pdf"
        rotate_pdf(test_pdf, output_file, rotation)
        rotated_pdfs.append(output_file)
        print(f"✅ {rotation}度回転したPDFを作成しました: {output_file}")

    print("📌 すべての回転PDFの作成が完了しました。")

    # PDF をマージ
    merged_pdf = "merged_output.pdf"
    merge_pdfs(merged_pdf, rotated_pdfs)
    print(f"✅ マージしたPDFを作成しました: {merged_pdf}")

    # GCS にアップロード
    gcs_bucket = "${PDF出力先のGCS名}"  # 🔹 ここにGCSのバケット名を指定
    gcs_destination = "merged_output.pdf"  # GCS上の保存名
    upload_to_gcs(gcs_bucket, merged_pdf, gcs_destination)

if __name__ == "__main__":
    main()

3.3.「requirements.txt」について

3.3.1.ライブラリ内容
項番 記載名 主な内容
1 PyPDF2 PDF の読み込み、ページの回転、マージ、保存などを行うライブラリ
2 reportlab PDF の生成、テキストや画像の描画を行うライブラリ
3 google-cloud-storage Google Cloud Storage (GCS) へのファイルアップロードを行うライブラリ
3.3.2.「requirements.txt」コード
PyPDF2==3.0.1
reportlab==3.6.12
google-cloud-storage

3.4.「Dockerfile」について

  • このままだと「Python 3.12」で構築され、PDFを生成するための「reportrab」の「freetype」関連のパッケージが不足してエラーとなる。
    そのため「Python 3.10」で環境を構築する。
3.4.1.「Dockerfile」コード
# Python 3.10 をベースにしたコンテナ
FROM python:3.10

# 必要なライブラリをインストール
RUN apt-get update && apt-get install -y \
    libfreetype6-dev libjpeg-dev libpng-dev \
    && rm -rf /var/lib/apt/lists/*

# 作業ディレクトリを設定
WORKDIR /app

# requirements.txt をコンテナ内にコピー
COPY requirements.txt .

# pip をアップグレードし、必要なライブラリをインストール
RUN pip install --upgrade pip setuptools wheel \
    && pip install -r requirements.txt

# デフォルトのコマンド(対話シェル)
CMD [ "python3" ]

4.ビルドの準備

4.1.Dockerイメージをビルド

  • Dockerfileに基づき「Python 3.10」の環境を持つ 「my-python-env」というイメージを作成
    cd ${フォルダ名}
    docker build -t my-python-env .

4.2.コンテナを起動・コンテナ内移動

  • Cloud Shell のディレクトリ(${フォルダ名))をコンテナで利用するため、「-v」オプションで「/app」にマウントしてファイル共有をする。

  • 「-v」により、Cloud Shell のファイルを直接コンテナ内でも操作可能となり、コンテナ内で出力されたPDFも、コンテナ終了後でもローカルに残せる。

  • 以下コマンドを実行することで、コンテナ内のシェルに入る。

    docker run --rm -it -v $(pwd):/app my-python-env /bin/bash
  • 動作確認
    ・Pythonのバージョン確認
    ・reportlabの稼働確認

    python --version
    python -c "import reportlab; print(reportlab.Version)"

5.アプリ実行

  • 仮想環境の有効化

    python app.py
  • コンテナの起動・終了コマンド
    今回「–rm」オプションで起動しているため、「exit」したらコンテナは削除される挙動をとります。

  • Cloud Shellは一定時間操作がないと自動で停止するため、コンテナを放置しても自動で停止しますが、念のため停止させましょう。

項番 内容 コマンド
1 起動 docker run –rm -it -v $(pwd):/app my-python-env /bin/bash
2 終了 exit

6.実行結果

6.1.コンソールでの見え方

root@76be6a0c3061:/app# python app.py 
📌 回転したテスト用PDF作成 + マージ + GCSアップロード スクリプト
✅ テスト用PDFを作成しました: test.pdf
✅ 0度回転したPDFを作成しました: rotated_0.pdf
✅ 90度回転したPDFを作成しました: rotated_90.pdf
✅ 180度回転したPDFを作成しました: rotated_180.pdf
✅ 270度回転したPDFを作成しました: rotated_270.pdf
📌 すべての回転PDFの作成が完了しました。
Adding rotated_0.pdf to merged PDF
Adding rotated_90.pdf to merged PDF
Adding rotated_180.pdf to merged PDF
Adding rotated_270.pdf to merged PDF
Successfully merged into merged_output.pdf
✅ マージしたPDFを作成しました: merged_output.pdf
Uploaded merged_output.pdf to gs://before-change-bucket/merged_output.pdf

6.2.GCSのフォルダ構成

  • 「GCS」にもオブジェクトが作成されていることが画面からもわかります。
    file

  • 作成されたPDFの内容。それぞれ90度ずつ4枚作成されています。
    file

おわりに

得られた知見

  • GoogleCloud Shellでのコンテナ実行方法
  • Cloud Shell 上での Docker の使い方

今後の課題

  • AWS環境でも同様の手順をハンズオンする。
  • Cloud Shellだけでなく、Cloud Run や Cloud Functions へのデプロイに挑戦する。
Last modified: 2025-03-16

Author