OCIのFunctionって、使ってますか

流行りのサーバーレスですね

で、この Function から、kubernetes を制御したいなと思いました。

最初、簡単に出来るだろーと思ってたんですが、認証の仕方が、わからなくて困りました。

このようなサーバーレスの環境から kubernetes API を叩くには、サービスアカウントを使って、トークンを指定する必要があるらしいです。

それと、FunctionサービスにIAM権限は、要りますよ。

対象Function用に 動的グループを作って、それに use cluster-family でも与えれば OK です。

Allow dynamic-group acme-func-dyn-grp to use cluster-family in tenancy

適当に cluster-family とかってしてますけど、もうちょっと絞り込めそうですけどね。


では、そのサービスアカウントって、どうやって作るのかと

kubectlを使って作りますよ

まず、サービスアカウント構築
kubectl -n kube-system create serviceaccount kubeconfig-sa

次に、クラスターロールバインディング構築
kubectl create clusterrolebinding add-on-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:kubeconfig-sa

ここは、よくわからなかったので、cluster-admin とかって指定してます。

もっと、しょぼいのを指定するべきなんでしょうね。

 

作ったサービスアカウントのシークレットを登録することで、トークンを取り出せます。
token.yaml
apiVersion: v1
kind: Secret
metadata:
  name: oke-kubeconfig-sa-token
  namespace: kube-system
  annotations:
    kubernetes.io/service-account.name: kubeconfig-sa
type: kubernetes.io/service-account-token

kubectl apply -f ./token.yaml

kubectl describe secrets oke-kubeconfig-sa-token -n kube-system

Name:         oke-kubeconfig-sa-token
Namespace:    kube-system
Labels:       kubernetes.io/legacy-token-last-used=2024-01-17
Annotations:  kubernetes.io/service-account.name: kubeconfig-sa
              kubernetes.io/service-account.uid: 622d38cd-1234-567e-8f2c-82b7db0c36b8
 
Type:  kubernetes.io/service-account-token
 
Data
====
ca.crt:     1285 bytes
namespace:  11 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6ImhmREVVbXhEbE4yR19ZQXRjQXhfTzN5VUMweDV4cE5DeVhRX0FTb2hlM1UifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNhogehogeBhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJva2Uta3ViZWNvbmZpZy1zYS10b2tlbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2hogehogehogehogeWJlY29uZmlnLXNhIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiNjIyZDM4Y2QtNzM0Ni00NDBlLThmMmMtODJiN2RiMGMzNmI4Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmt1YmVjb25maWctc2EifQ.HtrUn1jHEd8eO3uE4E8HnVL_PknOSvdZ0eKZbdVj_pa_HxaDwRBbUjA9f42Ss-yvxzV8acecoN9U5VettCEwex-yP_PcVo7xa9UBqN-kWY-9Kv1JLK1oVwJlx3wMk-vv-FTGIqrujNZKY6dVjn4yYKTMVhDly8Pj6MzWXeb5y4hogehogehogehogeDcP690ywtc-oaAfKMs2rj5ExRKsYy5HPBD1QDYjHrHEtelaJyiaWORVhiR27DfAA7VV5v5qFfl82Cuqqx-80iHKtfR-MQi_Eo5YVL76Pi-sKBvsbnPFx_5ExfvXgB3SIwVVi_WD2NektWwC1guRQrBZwAR_g

 

で、token が出力されるので、これをFunctionで、使えばアクセス出来ます。

 

では、Functionのサンプルです。

Func.py

import io
import json
import logging
import yaml
import oci

from kubernetes import client, config                                     

from fdk import response

def handler(ctx, data: io.BytesIO = None):
    result = ""

    # OKE Cluster OCID
    cid = "ocid1.cluster.oc1.ap-osaka-1.aaaaaaaatplc3goddiojjxhyyn6j4oxxitgfhogehogeizsconoginupxa"
    try:
        # Function auth information
        signer = oci.auth.signers.get_resource_principals_signer()

        # Build OKE Client
        ce_client : oci.container_engine.ContainerEngineClient = oci.container_engine.ContainerEngineClient({}, signer=signer)
        # Build Cluster config
        res : oci.response.Response = ce_client.create_kubeconfig(cluster_id=cid)
        result = res.data.text

        # Cluster config load
        kubeconfig2 = yaml.load(result,Loader=yaml.FullLoader)
        config.load_kube_config_from_dict(kubeconfig2)

        # Set ServiceAccount's token
        apiclient = config.new_client_from_config_dict(kubeconfig2)
        apiclient.configuration.api_key['authorization'] = 'eyJhbGciOiJSUzI1NiIsImtpZCI6ImhmREVVbXhEbE4yR19ZQXRjQXhfTzN5VUMweDV4cE5DeVhRX0FTb2hlM1UifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNhogehogeBhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJva2Uta3ViZWNvbmZpZy1zYS10b2tlbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2hogehogehogehogeWJlY29uZmlnLXNhIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiNjIyZDM4Y2QtNzM0Ni00NDBlLThmMmMtODJiN2RiMGMzNmI4Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50Omt1YmUtc3lzdGVtOmt1YmVjb25maWctc2EifQ.HtrUn1jHEd8eO3uE4E8HnVL_PknOSvdZ0eKZbdVj_pa_HxaDwRBbUjA9f42Ss-yvxzV8acecoN9U5VettCEwex-yP_PcVo7xa9UBqN-kWY-9Kv1JLK1oVwJlx3wMk-vv-FTGIqrujNZKY6dVjn4yYKTMVhDly8Pj6MzWXeb5y4hogehogehogehogeDcP690ywtc-oaAfKMs2rj5ExRKsYy5HPBD1QDYjHrHEtelaJyiaWORVhiR27DfAA7VV5v5qFfl82Cuqqx-80iHKtfR-MQi_Eo5YVL76Pi-sKBvsbnPFx_5ExfvXgB3SIwVVi_WD2NektWwC1guRQrBZwAR_g'
        apiclient.configuration.api_key_prefix['authorization'] = 'Bearer'

        # Build Kubernetes client
        v1 = client.CoreV1Api(apiclient)
        namespace = 'default'
        label = 'app=wheretrainsvc-service'
        svclist = v1.list_namespaced_service(namespace,label_selector=label)
        for svc in svclist.items:                                                
            result = svc.status.load_balancer.ingress[0].ip

    except (Exception, ValueError) as ex:
        logging.getLogger().info('error: ' + str(ex))
        return response.Response(
            ctx, response_data= "Error:"+str(ex),
            headers={"Content-Type": "application/text"}
        )

    return response.Response(
        ctx, response_data= result,
        headers={"Content-Type": "application/text"}
    )
 

requirements.txt

fdk>=0.1.66
kubernetes
oci
pyyaml

 

Serviceの IP アドレスを取得する Functionとなります。

こんな感じ叩くと、IP アドレスが、ポロっと出力されます。

oci fn function invoke --function-id ocid1.fnfunc.oc1.ap-osaka-1.aaaaaaaa7lgs7z6nhhogehoge57d7wfvlj2bbmakpt4hj3vczgt6ayp2q --file "-" --body ''

 

 

Joomla templates by a4joomla