なかなか、そのままのタイトルですが
なんで、そんなことしたいかと言うと、実行しているPodの中でバックアップ処理を外からさせたいからです。
kubectlが実行出来る環境を構築すれば良いんですが、面倒なので、Pythonだけでなんとかしたかったのですよ
func.py
import sys
import io
import json
import logging
import yaml
import oci
from kubernetes import client, config
from kubernetes.client.rest import ApiException
from kubernetes.stream import stream
from fdk import response
# Execute command to Pod.
def exec_commands(api_instance : client.CoreV1Api, podname, commands, loopwait=10, namespace = 'default' ):
result=""
name = podname
resp = api_instance.read_namespaced_pod(name=name,
namespace=namespace)
if not resp:
raise Exception('not', 'resp')
# Calling exec interactively
exec_command = ['/bin/sh']
resp = stream(api_instance.connect_get_namespaced_pod_exec,
name,
namespace,
command=exec_command,
stderr=True, stdin=True,
stdout=True, tty=False,
_preload_content=False)
max_loop=loopwait
loop=0
while resp.is_open():
sout = resp.readline_stdout(timeout=1)
if sout is not None :
result += (sout + '\n')
loop=0
if resp.peek_stderr():
print( resp.read_stderr(), file=sys.stderr)
if commands:
c = commands.pop(0)
resp.write_stdin(c + "\n")
loop=0
else:
if loop > max_loop :
break
loop+=1
resp.close()
return result
def handler(ctx, data: io.BytesIO = None):
result = ""
# OKE Cluster OCID
cid = ""
apikey = ''
podname = ''
commands = []
try:
# Jsonロード
body = json.loads(data.getvalue())
bdata = body.get("data")
cid = bdata['clusterid']
apikey = bdata['apikey']
podname = bdata['podname']
for cmd in bdata['commands']:
commands.append( cmd )
# 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)
kconfig = res.data.text
# Cluster config load
kubeconfig2 = yaml.load(kconfig,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'] = apikey
apiclient.configuration.api_key_prefix['authorization'] = 'Bearer'
# Build Kubernetes client
v1 = client.CoreV1Api(apiclient)
result = exec_commands(v1, podname, commands, loopwait=10, namespace = 'default' )
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
これを fn やら、oci fn なんかで呼びだせば Ok です。
APIGatewayから呼び出せるようにすれば、何かと便利ですね。
oci fn function invoke --function-id ファンクションOCID --file "-" --body '
{
"data": {
"clusterid" : "クラスタOCID",
"apikey" : "サービスアカウントのトークン",
"podname" : "ポッド名",
"commands" : [コマンド]
}
}'
サービスアカウントのトークンは、以下を参考にして下さい。
OCI の Functionで、OKE(kubernetes) を制御したい