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.yamlapiVersion: 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 ''