Code EngineのアプリをCLIを利用してデバッグする方法

Code Engineにデプロイしたアプリがうまく起動しなかったり、エラーになった場合、CLIを利用してデバッグのための情報を集めたくなると思います

今回はibmcloud cliと、そしてkubectlを利用して、アプリをデバッグする方法を確認してみました

## コマンドだけサクッと知りたい方

- プロジェクトの選択
    - `ibmcloud ce project select -n <プロジェクト名>`
- アプリの詳細情報確認
    - `ibmcloud ce app get --name <アプリ名>`
- アプリのログ確認
    - `ibmcloud ce app logs --application <アプリ名>`
- kubectlを利用するためのkubeconfigの取得
    - `ibmcloud ce project select -n <プロジェクト名> --kubecfg`
- kubectlを利用してコンテナ内でのコマンド実行
    - `kubectl exec -it -c user-container <インスタンス名(Pod名)> -- bin/sh`

## 1. CLIのインストール

まず初めに必要なCLIをインストールします

kubectlは実行中のインスタンスでのコマンド実行を行いたい場合にインストールしてください

1. ibmcloud cli のインストール
   
    [https://cloud.ibm.com/docs/cli?topic=cli-getting-started](https://cloud.ibm.com/docs/cli?topic=cli-getting-started)
    
    MacOS の場合、次のコマンドを実行しcliのインストールを行います
    
    ```bash
    $ curl -fsSL https://clis.cloud.ibm.com/install/osx | sh
    ```
    
    インストールできたことの確認します
    
    ```bash
    $ ibmcloud version
    ```
    
    以下のようにバージョン情報が表示されていればOKです
    
    ```bash
    $ ibmcloud version    
    ibmcloud 2.31.0 (6b1eddc-2024-12-05T17:30:20+00:00) 
    Copyright IBM Corp. 2014, 2024
    ```
    
2. code engine pluginのインストール
   
    ibmcloud cliでcode engineの操作ができるようにプラグインをインストールします
    
    ```bash
    $ ibmcloud plugin install code-engine
    ```
    
    インストールできたことを確認します
    
    ```bash
    $ ibmcloud plugin list
    ```
    
    以下のようにプラグインリストにcode engineが表示されればOKです
    
    ```bash
    $ ibmcloud plugin list  
    Listing installed plug-ins...
    
    Plugin Name                                     Version   Status             Private endpoints supported
    cloud-functions[wsk/functions/fn]               1.0.83                       false
    cloud-logs[logs]                                0.1.2                        true
    cloud-object-storage                            1.10.0                       true
    code-engine[ce]        << ここ                   1.50.8                       true          
    ```
    
3. kubectlのインストール
   
    こちらを参考にインストールしてください
    
    [macOS上でのkubectlのインストールおよびセットアップ | Kubernetes](https://kubernetes.io/ja/docs/tasks/tools/install-kubectl-macos/)
    
    例 Homebrewを使用してmacOSへインストール
    
    ```bash
    $ brew install kubectl
    ```
    
    インストールできたことの確認
    
    ```bash
    kubectl version --client
    ```
    
    以下のように表示されればOKです
    
    ```bash
    $ kubectl version --client
    Client Version: v1.32.0
    Kustomize Version: v5.5.0
    ```
    

## 2. プロジェクトへのアクセス

1. ibmcloud cli でログインします
   
    ```bash
    $ ibmcloud login
    ```
    
    ちなみに余談ですが、API-Keyを利用してログインする方法がIDやパスワード入力の手間を省けて、個人的には便利で好きです
    
    参照：[IBM Cloud: ibmcloudコマンドでAPI Keyを使ってログインする方法 #ShinobiLayer - Qiita](https://qiita.com/testnin2/items/3ff57e6c92eacd664ff3)
    
    ```bash
    $ ibmcloud login --apikey @ibmcloud_apikey_file_path
    ```

2. 次に、Code Engine プロジェクトが作成されているリソースグループを選択します
    ```bash
    $ ibmcloud target -g resource_group_name
    
    # 例
    $ ibmcloud target -g satokota-rg
    ```
    
2. code engine プロジェクトの選択します
   
    ```bash
    $ ibmcloud ce project select -n project_name
    
    # 例
    $ ibmcloud ce project select -n satokota-project
    ```
    
3. kubectlを利用する際は、先程のプロジェクト選択コマンドに、一つオプションを追加するだけです
   
    ```bash
    $ ibmcloud ce project select -n project_name --kubecfg
    # 例
    $ ibmcloud ce project select -n satokota-project --kubecfg
    ```
    
4. プロジェクトにアクセスできているか確認してみます
   
    **ibmcloud ce**
    
    ```bash
    $ ibmcloud ce app list
    ```
    
    実行結果
    
    ```bash
    $ ibmcloud ce app list                                                             
    Listing all applications...
    OK
    
    Name                              Status  URL                                                                                      Latest                                  Age   Conditions  Reason  
    application-demo                  Ready   https://application-demo.xxxx.jp-tok.codeengine.appdomain.cloud                          application-demo-00001                  115m  3 OK / 3      
    application-web                   Ready   https://application-web.xxxxx.jp-tok.codeengine.appdomain.cloud                          application-web-00001                   76m   3 OK / 3        
    ```
    
    **kubectl**
    
    ```bash
    $ kubectl get deploy
    ```

    実行結果
    ```bash

    $ kubectl get deploy
    NAME                                                READY   UP-TO-DATE   AVAILABLE   AGE
    application-demo-00001-deployment                   1/1     1            1           92m
    application-web-00001-deployment                    0/0     0            0           83d
    ```

## 3. 確認用のアプリを作成

デバッグを試すためのアプリとしてnginxをCode Engine上にデプロイします

```bash
$ ibmcloud ce app create --name debug-test \
  --image nginx \
  --cpu 0.125 --memory 250M \
  --min-scale 1 --max-scale 1 \
  --port 80 
```

コマンド実行後、OKと表示され、アプリへのアクセスURLが確認できます

```bash
$ ibmcloud ce app create --name debug-test \
  --image nginx \
  --cpu 0.125 --memory 250M \
  --min-scale 1 --max-scale 1 \
  --port 80 
Creating application 'debug-test'...
The Route is still working to reflect the latest desired specification.
Configuration 'debug-test' is waiting for a Revision to become ready.
Ingress has not yet been reconciled.
Waiting for load balancer to be ready.
Run 'ibmcloud ce application get -n debug-test' to check the application status.
OK

https://debug-test.xxx.jp-tok.codeengine.appdomain.cloud
```

## 4. アプリの詳細確認

`ibmcloud ce app get --name <アプリ名>`

アプリのURLや、設定された環境変数、ポート番号、実行しているコンテナイメージ、イベント、割り当てられたリソース、実行中のインスタンス名などの情報がまとめて確認できます

まずはこのコマンドでポート番号があっているか、環境変数は正しく定義できているかなど確認するのがよさそうです

例

```bash
$ ibmcloud ce app get --name debug-test     
For troubleshooting information visit: https://cloud.ibm.com/docs/codeengine?topic=codeengine-troubleshoot-apps.
Run 'ibmcloud ce application events -n debug-test' to get the system events of the application instances.
Run 'ibmcloud ce application logs -f -n debug-test' to follow the logs of the application instances.
OK

Name:               debug-test  
ID:                 xxxxx-xxxxx-xxxx-xxx-xx  
Project Name:       xxxxxxxxx 
Project ID:         xxxxx-xxxxx-xxxxx-xxxxx-xxxxx  
Age:                4m45s  
Created:            2024-12-13T15:30:01+09:00  
URL:                https://debug-test.xxxxx.jp-tok.codeengine.appdomain.cloud  
Cluster Local URL:  http://debug-test.xxxxx.svc.cluster.local  
Console URL:        https://cloud.ibm.com/codeengine/project/jp-tok/xxxxx/application/debug-test/configuration  
Status Summary:     Application deployed successfully  

Environment Variables:    
  Type     Name             Value  
  Literal  CE_API_BASE_URL  https://api.jp-tok.codeengine.cloud.ibm.com  
  Literal  CE_APP           debug-test  
  Literal  CE_DOMAIN        jp-tok.codeengine.appdomain.cloud  
  Literal  CE_PROJECT_ID    xxxxxxxxxx  
  Literal  CE_REGION        jp-tok  
  Literal  CE_SUBDOMAIN     xxxxxxxxxx  
Image:                  nginx  
Resource Allocation:      
  CPU:                0.125  
  Ephemeral Storage:  400M  
  Memory:             250M  
Port:                   80  

Revisions:          
  debug-test-00001:    
    Age:                4m45s  
    Latest:             true  
    Traffic:            100%  
    Image:              nginx (pinned to fb1975)  
    Running Instances:  1  

Runtime:            
  Concurrency:       100  
  Maximum Scale:     1  
  Minimum Scale:     1  
  Scale Down Delay:  0  
  Timeout:           300  

Readiness Probe:    
  Type:  tcp  
  Port:  0 (use listening port)  

Conditions:         
  Type                 OK    Age    Reason  
  ConfigurationsReady  true  4m34s    
  Ready                true  4m30s    
  RoutesReady          true  4m30s    

Events:             
  Type    Reason   Age    Source              Messages  
  Normal  Created  4m46s  service-controller  Created Configuration "debug-test"  
  Normal  Created  4m46s  service-controller  Created Route "debug-test"  

Instances:          
  Name                                         Revision          Running  Status   Restarts  Age  
  debug-test-00001-deployment-d686d4774-bmjqf  debug-test-00001  3/3      Running  0         4m44s  
```

## 5. アプリのログ確認

`ibmcloud ce app logs --application <アプリ名>` 

デバッグといえばログ！ということで、ログを見てみます

ibmcloud ce app logsには  `--application` オプションと `--instance` オプションがあります

特定のインスタンスにしぼりたい場合は `ibmcloud ce app get --name <アプリ名>`を利用してインスタンス名の確認して実行します

例

```bash
$ ibmcloud ce app logs --application debug-test
Getting logs for all instances of application 'debug-test'...
OK

debug-test-00001-deployment-d686d4774-bmjqf/user-container:    
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration  
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/  
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh  
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf  
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf  
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh  
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh  
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh  
/docker-entrypoint.sh: Configuration complete; ready for start up  
2024/12/13 06:30:10 [notice] 1#1: using the "epoll" event method  
2024/12/13 06:30:10 [notice] 1#1: nginx/1.27.3  
2024/12/13 06:30:10 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14)   
2024/12/13 06:30:10 [notice] 1#1: OS: Linux 5.4.0-200-generic  
2024/12/13 06:30:10 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576  
2024/12/13 06:30:10 [notice] 1#1: start worker processes  
2024/12/13 06:30:10 [notice] 1#1: start worker process 29  
... 
127.0.0.1 - - [13/Dec/2024:06:31:07 +0000] "GET / HTTP/1.1" 200 615 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" "172.30.127.128, 127.0.0.6, 127.0.0.6"  
2024/12/13 06:31:07 [error] 42#42: *14 open() "/usr/share/nginx/html/favicon.ico" failed (2: No such file or directory), client: 127.0.0.1, server: localhost, request: "GET /favicon.ico HTTP/1.1", host: "debug-test.1j94jd9qgc0e.jp-tok.codeengine.appdomain.cloud", referrer: "https://debug-test.1j94jd9qgc0e.jp-tok.codeengine.appdomain.cloud/"  
127.0.0.1 - - [13/Dec/2024:06:31:07 +0000] "GET /favicon.ico HTTP/1.1" 404 555 "https://debug-test.1j94jd9qgc0e.jp-tok.codeengine.appdomain.cloud/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" "172.30.127.128, 127.0.0.6, 127.0.0.6"  

```

## 6. 実行中インスタンスでのコマンド実行による確認

`kubectl exec -it <インスタンス名(Pod名)> --container user-container -- bin/sh`  

実行中のインスタンスでコマンドが実行できると、設定の確認や、一時的に設定を書き換えてみてのテストなども行えるので便利ですね

> 実行しているコンテナイメージにてshが実行可能という前提です
scratchイメージベースなどシェルが含まれていないコンテナではコマンド実行できません
そういう場合にデバッグのために別のコンテナを差し込む方法（EphemeralContainers）方法があり、そちらが便利なのですが、Code Engineでは権限がなさそうで利用できませんでした

0. kubectlでプロジェクトにアクセスできるようにkubeconfigを取得する

    ```bash
    $ ibmcloud ce project select -n project_name --kubecfg
    ```
    
1. インスタンス名(Pod名)を確認します
   
    ```bash
    $ kubectl get pod
    ```
    
    実行結果
    
    ```bash
    $ kubectl get pod
    NAME                                                      READY   STATUS    RESTARTS   AGE
    debug-test-00001-deployment-d686d4774-bmjqf               3/3     Running   0          27m
    ```
    
2. execコマンドを利用しコンテナ内でコマンドを実行できるようにします
   
    ```bash
    $ kubectl exec -it debug-test-00001-deployment-d686d4774-bmjqf -c user-container -- bin/sh
    ```
    
    実行例
    
    コンテナ内でenvコマンドで環境変数を確認したり、localhostで接続できることを確認したり、nginx.confの設定を確認したりしてみます
    
    ```bash
    $ kubectl exec -it debug-test-00001-deployment-d686d4774-bmjqf -- bin/sh
    
    # env
    CE_REGION=jp-tok
    KUBERNETES_PORT=tcp://172.21.0.1:443
    KUBERNETES_SERVICE_PORT=443
    HOSTNAME=debug-test-00001-deployment-d686d4774-bmjqf
    K_REVISION=debug-test-00001
    ...
    PORT=80
    HOME=/root
    
    # curl localhost
    <!DOCTYPE html>
    <html>
    <head>
    <title>Welcome to nginx!</title>
    ...
    </body>
    </html>
    
    # cat etc/nginx/nginx.conf
    
    user  nginx;
    worker_processes  auto;
    
    error_log  /var/log/nginx/error.log notice;
    pid        /var/run/nginx.pid;
    
    events {
        worker_connections  1024;
    }
    
    http {
        ...
    }
    ```
    

## 参考情報

- [アプリのデバッグ | IBM Cloud 資料](https://cloud.ibm.com/docs/codeengine?topic=codeengine-troubleshoot-apps)
- [Code Engine での Kubernetes の使用 | IBM Cloud 資料](https://cloud.ibm.com/docs/codeengine?topic=codeengine-kubernetes)
- [Code Engine での Knative の使用 | IBM Cloud 資料](https://cloud.ibm.com/docs/codeengine?topic=codeengine-knative)