0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Podman のREST APIを使ってコンテナ内にファイルを配置する

Posted at

Podman REST APIを使用してコンテナにファイルをコピーする方法

はじめに

Podmanは、コンテナ管理のための強力なツールです。本記事では、PythonからPodman REST APIを使用してコンテナにファイルをコピーする方法について解説します。

特に、公式ドキュメントには記載されていない重要な点について詳しく説明します。

Podman REST APIの基本

Podman はコンテナのためのツールですが REST API を提供しており、プログラマブルに制御できます。ここでは Python で扱える podmanモジュールを使用します。

このモジュールは基本的な操作をサポートしていますが、コンテナ内にファイルをコピーするAPIは含まれていません。

コンテナへのファイルコピーの実現

モジュールにない操作はPodman HTTP APIドキュメントを参照すれば実装は難しくありません。ファイルコピーについても記載されています。

しかし、ファイルコピーについてはドキュメントの記載が間違っており、その通りにやっても動作しません。

Podman Issue Screenshot

問題点

結論から言うと、ファイルコピーについてはドキュメントに記載されているContent-Typeが正しくありませんでした。これに類似する問題については、Podmanのissue #21861でも報告されています。

正常だと主張する HTTP Status を返すものの、求める動作をしていない状況です。

解決策

ひとつひとつトラブルシューティングを行いました。

まずは podman の cli が動作するだろうと考え、以下のコマンドで正常にファイルをコピーできることを確認しました。

podman container cp ./trial.py sandbox:/home

コピーの確認:

podman container exec -it sandbox /bin/bash
# ls -al /home

CLIの実装調査

動作確認が取れたので cli のコードを読んでいきます。

Podmanのソースコードを調査した結果、containers/archive.goが該当する処理を行っていることが分かりました。

DoRequest で HTTP リクエストを送っています。DoRequestの実装を見るとheaderを受け取るようになっていますが、archive.goからはnilが渡されていました。

このことから、ドキュメントに記載があったJSON形式での送信は不要であることが判明しました。

Pythonによる実装例

原因が判明したので requests モジュールで実装します。

以下に、PythonでPodman REST APIを使用してコンテナにファイルをコピーする完全な実装例を示します

from podman import PodmanClient
import tarfile
import io

def create_tar_string(file_name: str, file_content: str) -> str:
    """tarファイルを作成し、文字列として返す"""
    buffer = io.BytesIO()
    
    with tarfile.open(fileobj=buffer, mode="w") as tar:
        info = tarfile.TarInfo(name=file_name)
        info.size = len(file_content)
        file_bytes = file_content.encode('utf-8')
        
        tar.addfile(info, io.BytesIO(file_bytes))    
    tar_string = buffer.getvalue().decode('utf-8')
    return tar_string

uri = "unix:///run/user/1000/podman/podman.sock"
with PodmanClient(base_url=uri) as client:
    version = client.version()
    print("Release: ", version["Version"])
    print("Compatible API: ", version["ApiVersion"])
    print("Podman API: ", version["Components"][0]["Details"]["APIVersion"], "\n")

    image_name = "docker.io/library/python:3.11-slim"
    client.images.pull(image_name)

    container_name = "sandbox"
    container = client.containers.create(
        image_name,
        name="sandbox",
        command=["python", "-c", "import time; time.sleep(3600)"],  # コンテナを起動したまま保持
        detach=True
    )

    # コンテナの起動
    container.start()

    # ファイルコピーするために tarfile を作成
    tar_string = create_tar_string("trial.py", "print('Hello, World!')")
    
    # 【ファイルコピー】
    response = client.api.put(f"/containers/{container_name}/archive", params={"path": "/home"}, data=tar_string)
    print(response.status_code)
    print(response.text)

    # コンテナ内で転送したファイルをそのまま実行
    exit_code, output = container.exec_run("python /home/trial.py")
    print(f"Exit code: {exit_code}")
    print(f"Output: {output.decode()}")

    # コンテナの停止と削除
    container.stop()
    container.remove()

このコードは以下の手順で動作します:

  1. Podmanクライアントの初期化
  2. Pythonイメージのプル(docker.ioは省略できません)
  3. コンテナの作成と起動
  4. 転送したいファイルの Tar file 化
  5. ファイルのコピー
  6. コピーしたファイルを実行
  7. コンテナの停止と削除

重要なポイント

  1. ファイルコピーAPIではPUTメソッドでの通信になります。またJSONを送信しません
  2. create_tar_string 関数を使用して、コピーするファイルをtar形式に変換します
  3. ファイルコピーにはclient.api.putメソッドを使用し、クエリパラメータとしてコピー先のパスを指定します
  4. ファイルが正しくコピーされなかった場合でも200ステータスコードが返される可能性があるため、実際にファイルが存在するか確認することをおすすめします

まとめ

Podman REST APIを使用してコンテナにファイルをコピーする方法について解説しました。公式ドキュメントには記載されていない重要な点もありますが、本記事で紹介した方法を使用することで、ファイルコピーを実装できます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?