はじめに
今回はChatGPTを使って簡単なゲームアプリケーションを作成し、IBM Cloud Kuberenetes Services(IKS)に載せて動かしてみる検証を行いました。全体的な流れを記述するとともに、問題なくアプリケーションがデプロイされたことを確認することを目的として作業しました。
前提条件
・今回の内容にはIBM Cloudのアカウント(無料利用可能)が前提となっています。
・この記事でのコマンドは全てMacOS向けとなっています。
ChatGPTを使ってコードを書いてもらう
まず、ChatGPTを使ってゲームアプリケーションを作成してもらいます。注意点としては、すでにご存知の方も多いかと思いますが、ChatGPTは間違った情報も堂々と正解のように教えてくれるケースも少なくないので、現時点ではその情報の見分けが必要です。
簡単なゲームアプリを作成するに、今回はpygameを選びました。pygameは、ビデオゲームを製作するために設計されたクロスプラットフォームのPythonモジュール集です。使用する言語はもちろんPythonとなります。
pygameが初めての方は、以下のコマンドでInstallを実施します。
pip install pygame
以下、pygameでゲームを作成するために早速ChatGPTに質問を投げます。
pygameコードで何かできるものはない?
pygameを使用して実現できる様々な機能やゲームのアイデアがあります。以下にいくつかの例を挙げます:
1. スペースインベーダーゲーム: プレイヤーシップを操作して、降りてくる敵の攻撃を避けながら撃墜するゲームです。
2. パズルゲーム: ピースを動かして絵やパターンを完成させるゲームです。例えば、スライディングパズルやジグソーパズルなどがあります。
3. プラットフォームゲーム: ジャンプや障害物回避をしながらレベルを進めるゲームです。例えば、マリオやソニックのようなゲームがあります。
4. シューティングゲーム: プレイヤーが敵を撃破するために武器を使用するゲームです。例えば、縦スクロールシューティングや横スクロールシューティングなどがあります。
5. レースゲーム: プレイヤーが車やバイクを操作して他の競技者と競い合うゲームです。例えば、カートゲームやレーシングシミュレータなどがあります。
と、何種類かのゲームを教えてくれます。
私は1番のスペースインベーダーゲームが気になったので、そのコードを書いてもらうように要請しました。
1番のスペースインベーダーゲームのコマンドを教えて
以下に、基本的なスペースインベーダーゲームのコードを示します。このコードはpygameを使用してスペースインベーダーゲームを作成するためのものです。以下のコードを実行すると、ゲームウィンドウが表示され、プレイヤーシップと敵のスペースインベーダーが表示されます。プレイヤーシップは矢印キーで移動し、スペースキーで弾を発射することができます。
import pygame
import random
# 初期化
pygame.init()
# ゲームウィンドウの作成
width = 800
height = 600
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Space Invaders")
# カラー定義
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
# プレイヤーシップの作成
player_width = 50
player_height = 50
player_x = width // 2 - player_width // 2
player_y = height - player_height - 10
player_speed = 5
player = pygame.Rect(player_x, player_y, player_width, player_height)
# スペースインベーダーの作成
invader_width = 40
invader_height = 40
invader_speed = 2
invaders = []
for row in range(5):
for col in range(10):
invader_x = col * (invader_width + 10) + 50
invader_y = row * (invader_height + 10) + 50
invader = pygame.Rect(invader_x, invader_y, invader_width, invader_height)
invaders.append(invader)
# 弾の作成
bullet_width = 5
bullet_height = 10
bullet_speed = 5
bullet = None
bullet_state = "ready" # "ready" or "fired"
# ゲームループ
running = True
clock = pygame.time.Clock()
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and bullet_state == "ready":
bullet_state = "fired"
bullet_x = player.x + player.width // 2 - bullet_width // 2
bullet_y = player.y
bullet = pygame.Rect(bullet_x, bullet_y, bullet_width, bullet_height)
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and player.x > 0:
player.x -= player_speed
if keys[pygame.K_RIGHT] and player.x < width - player_width:
player.x += player_speed
if bullet_state == "fired":
bullet.y -= bullet_speed
if bullet.y < 0:
bullet_state = "ready"
screen.fill(BLACK)
pygame.draw.rect(screen, WHITE, player)
for invader in invaders:
pygame.draw.rect(screen, WHITE, invader)
if bullet_state == "fired":
pygame.draw.rect(screen, WHITE, bullet)
pygame.display.update()
# 終了
pygame
上記のコードに加えて、銃を連打するコードを追加したり、敵の色を変更するなど、カスタマイズのためのコードも要請することで、コードを書けない人でも簡単にゲームを作成することができます。
色々学習させた後の最終盤コードが以下となります。
import pygame
import random
# 初期化
pygame.init()
# ゲームウィンドウの作成
width = 800
height = 600
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("Space Invaders")
# カラー定義
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (128, 128, 128)
RED = (255, 0, 0)
# プレイヤーシップの作成
player_width = 50
player_height = 50
player_x = width // 2 - player_width // 2
player_y = height - player_height - 10
player_speed = 5
player = pygame.Rect(player_x, player_y, player_width, player_height)
# スペースインベーダーの作成
invader_width = 40
invader_height = 40
invader_speed = 2
invader_direction = 1
invaders = []
for row in range(5):
for col in range(10):
invader_x = col * (invader_width + 10) + 50
invader_y = row * (invader_height + 10) + 50
invader = pygame.Rect(invader_x, invader_y, invader_width, invader_height)
invaders.append(invader)
# 弾の作成
bullet_width = 5
bullet_height = 10
bullet_speed = 5
bullets = []
# 敵の攻撃
enemy_bullet_width = 3
enemy_bullet_height = 10
enemy_bullet_speed = 3
enemy_bullets = []
# スコア
score = 0
font = pygame.font.Font(None, 36)
# ゲームオーバーメッセージ
game_over_font = pygame.font.Font(None, 72)
# ゲームループ
running = True
clock = pygame.time.Clock()
def draw_score():
score_text = font.render("Score: " + str(score), True, WHITE)
screen.blit(score_text, (10, 10))
def draw_game_over():
game_over_text = game_over_font.render("Game Over", True, WHITE)
game_over_rect = game_over_text.get_rect(center=(width // 2, height // 2))
screen.blit(game_over_text, game_over_rect)
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
bullet_x = player.x + player.width // 2 - bullet_width // 2
bullet_y = player.y
bullet = pygame.Rect(bullet_x, bullet_y, bullet_width, bullet_height)
bullets.append(bullet)
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and player.x > 0:
player.x -= player_speed
if keys[pygame.K_RIGHT] and player.x < width - player_width:
player.x += player_speed
for bullet in bullets:
bullet.y -= bullet_speed
if bullet.y < 0:
bullets.remove(bullet)
for invader in invaders:
invader.x += invader_speed * invader_direction
if invader.x < 0 or invader.x > width - invader_width:
invader_direction *= -1
for invader in invaders:
invader.y += 20
if invader.colliderect(player):
running = False
if random.randint(0, 1000) < 5 and len(enemy_bullets) < 5:
enemy_bullet_x = invader.x + invader.width // 2 - enemy_bullet_width // 2
enemy_bullet_y = invader.y + invader.height
enemy_bullet = pygame.Rect(enemy_bullet_x, enemy_bullet_y, enemy_bullet_width, enemy_bullet_height)
enemy_bullets.append(enemy_bullet)
for bullet in bullets:
for enemy_bullet in enemy_bullets:
if bullet.colliderect(enemy_bullet):
bullets.remove(bullet)
enemy_bullets.remove(enemy_bullet)
for enemy_bullet in enemy_bullets:
enemy_bullet.y += enemy_bullet_speed
if enemy_bullet.colliderect(player):
running = False
if enemy_bullet.y > height:
enemy_bullets.remove(enemy_bullet)
for bullet in bullets:
for invader in invaders:
if bullet.colliderect(invader):
invaders.remove(invader)
bullets.remove(bullet)
score += 10
screen.fill(BLACK)
pygame.draw.rect(screen, WHITE, player)
for invader in invaders:
pygame.draw.rect(screen, GRAY, invader) # 灰色で描画
for bullet in bullets:
pygame.draw.rect(screen, WHITE, bullet)
for enemy_bullet in enemy_bullets:
pygame.draw.rect(screen, RED, enemy_bullet) # 赤色で描画
draw_score()
if len(invaders) == 0:
draw_game_over()
pygame.display.update()
# 終了
pygame.quit()
注意すべき点としては、上記の通り間違ったコードなども何回も与えられたため、結局細かい部分の修正が必要でした。ChatGPTに投げる質問が悪かったかもしれませんが、間違った場合にはChatGPTに間違った旨と正しく修正したコードを再度要請することである程度対応することができました。
作成できたコードはコードエディターに入れて扱いましたが、今回はVisual Studio Code(VScode)を使用しました。作成されたコードを実行するために、右上のプレーボタン
をクリックします。ゲーム画面が表示され、プレーすることが可能になります。
pygameをDockerfileに変換する
PythonのゲームをDockerイメージに変換するために、Dockerfileを作成する必要があります。
VSCodeでDockerfileを作成し、以下のコードを記載しておきます。
FROM python:3.11.3
WORKDIR /app
# ソースコードをコンテナ内の/appディレクトリにコピーする
COPY game.py .
# 必要なパッケージをインストールする
RUN pip install pygame
CMD ["python", "game.py"]
Docker Hubに格納する
アプリケーションの作成が完了したら、次にはアプリケーションのDockerイメージを作成し、Docker Hubに格納します。
注意点としては、以下の作業はDockerfileがあるディレクトリに移動してコマンドを実行する必要があります。
docker login
docker build -t game-test:latest .
docker tag space-invaders:latest <DockerHubのユーザ名>/space-invaders:latest
docker push <DockerHubのユーザ名>/space-invaders:latest
すると、Docker HubにDockerイメージが格納されたことが確認できます。
IKSクラスター上でデプロイ
アプリケーションを載せるために、IKSのクラスターを作成します。クラスター作成の具体的な流れは過去に作成したこちらの記事に書かれています。過去記事にはClassicクラスターを作成しましたが、今回はVPCクラスターを作成しています。
ターミナルにて、IBM Cloudにログインします。ログインはCLIを使用したワンタイム・パスコードを利用すると便利です。
右上のプロフィールアイコンをクリックし、CLIとAPIにログイン
をクリックしますと、以下のログインCLIが表示されます。
IBM Cloud CLIをコピーしコマンド入力にてログインを行います。
その後、以下のコマンドを使ってクラスターを指定します。
今回アプリケーションをデプロイするクラスターを指定します。
Kubernetesの環境を設定するには、exportコマンドが必要です。exportコマンドは、ibmcloud ks cluster config
コマンドを入力して取得します。
なお、クラスターIDはクラスター画面に表示されています。
ibmcloud ks cluster config --cluster <cluster-id>
<cluster-id> のコンテキストを現在の kubeconfig ファイルに追加しました。
これで、クラスターに対して「kubectl」コマンドを実行できます。 例えば、「kubectl get nodes」を実行します。
クラスターに初めてアクセスする場合、RBAC の同期中に「kubectl」コマンドが数秒間失敗することがあります。
IKSリソースの作成
Kubernetesリソースの作成: アプリケーションを実行するために必要なKubernetesリソースを定義します。一般的なリソースには、Deployment、Service、Ingressなどがあります。Deploymentはアプリケーションのコンテナを管理し、Serviceはアクセスを提供し、Ingressは外部からのトラフィックをルーティングする役割を持ちます。
今回はDeploymentとServiceのみ使用しています。
VSCodeにてDeploymentファイルとServiceファイルをyaml形式で作成します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: game-test
spec:
replicas: 1
selector:
matchLabels:
app: game-test
template:
metadata:
labels:
app: game-test
spec:
containers:
- name: game-test
image: sungyunmoon/space-invaders:latest
# resources:
# requests:
# cpu: "0.5"
# memory: "512Mi"
# limits:
# cpu: "1"
# memory: "1Gi"
ports:
- containerPort: 8080
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: game-test
spec:
selector:
app: game-test
ports:
- protocol: TCP
port: 80
targetPort: 8080
yamlファイルの作成が完了したら、ターミナルにて以下のコマンドを入力し、IKS上にデプロイを行います。
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
その後、以下コマンドにてデプロイを確認します。
kubectl get pods
kubectl get services
NAME READY STATUS RESTARTS AGE
game-test-5896d6c7b5-8n7k5 1/1 Running 1 (5s ago) 11s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
game-test ClusterIP 172.21.102.241 <none> 80/TCP 2m5s
kubernetes ClusterIP 172.21.0.1 <none> 443/TCP 3m7s
問題なくIKS上にデプロイされたことがわかります。
課題
IKSにデプロイした数分後、ターミナルで確認したところ、DeploymentのStatusにCrashLoopBackOff
というエラーが発生していました。念の為IKSのコンソールで確認しても赤色でBack-off restarting failed container
というエラーが表示されています。
sungyunmoon@at-Mac-Pro python % kubectl get pods
kubectl get services
NAME READY STATUS RESTARTS AGE
game-test-5896d6c7b5-8n7k5 0/1 CrashLoopBackOff 6 (2m6s ago) 8m22s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
game-test ClusterIP 172.21.102.241 <none> 80/TCP 8m22s
kubernetes ClusterIP 172.21.0.1 <none> 443/TCP 9m24s
あくまでも推測ですが、作成したアプリケーションは一回きりの実行がされていて、継続実行ができないコードとなっているため、このようなエラーが発生しているのではないかと思います。
こちらの詳細はまだ勉強が必要な部分であるため、解決でき次第追記できればと思います。
もしおわかりになる方は、コメントにてご指摘いただけますと幸いです。
最後に
今回はChatGPTでアプリケーションを作成し、IKS上にデプロイする流れを検証しまとめてみました。
私自身はコーディングは全くできない初心者で、IBM Cloudリソースの検証にはいつも事前に作られているサンプルアプリを使うことがほとんどでしたが、ChatGPTを利用することによって、初心者でも自分のアプリケーションを作成して動かしてみることができるのは楽しい作業となりました。
また、IBM Cloud上にはCode Engineをはじめとするクラウドネイティブ向けの数多いサービスがありますが、今回手作業でアプリケーションをデプロイしてみることによって、Code Engineなどのサービスがどれほど楽で有効なサービスなのかも改めて感じました。