使用Python来使用Docker和Kubernetes,在Docker中使用Docker,在Kubernetes中使用Kubernetes
使用Python通过Docker和Kubernetes,通过Docker使用Docker,通过Kubernetes使用Kubernetes。
Docker和Kubernetes通常都会使用Bash进行操作,文档也是以Bash为前提编写的。
然而,Docker和Kubernetes都公开了API,因此可以使用除Bash以外的其他方式进行操作。
例如,Docker官方提供了用于DockerEngine的Golang和Python的客户端SDK,而Kubernetes也有用于Python的客户端。
-
- Docker Engine用のGolang、PythonクライアントSDK
-
- https://docs.docker.com/develop/sdk/
KubernetesのPython用クライアント
https://github.com/kubernetes-client/python
Bash以外からDockerやKubernetesを使うメリットは、非インフラエンジニアでも得意な言語でDockerやKubernetesを操作できるようになる点で、Infrastructure as Codeの一端になると思います。
というわけで、今回はPythonでDockerやKubernetesを操作してみたいと思います。
またついでに、DockerコンテナからDockerを、Kubernetes PodsからKubernetesを操作します。
このあたりは道楽で試してみたらできたことを共有するだけです。
我这次写的代码。
做的事情 (zuò de
构成如下。
主机操作系统:CentOS7
Docker版本:ce 17.03
用于Python客户端的Docker容器:CentOS7
Python版本:3.6
Kubernetes集群:1个主节点
Kubernetes版本:1.9
准备好
请参考官方文档安装Docker和Kubernetes在CentOS7上。
https://docs.docker.com/install/
https://kubernetes.io/docs/setup/independent/create-cluster-kubeadm/
如果已经安装了Docker和Kubernetes,那么我们就准备一个用于Python客户端的Docker容器。无论是Python客户端还是Kubernetes客户端,都可以通过pip install安装,因此我们会在创建容器镜像的同时安装它们。
pip install docker kubernetes
个人创建的Docker镜像的Dockerfile如下,但首先只需要能运行Python3.6即可。
FROM centos:latest
MAINTAINER CVUSK
ENV container docker
RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;
VOLUME [ "/sys/fs/cgroup" ]
# yum install packages
RUN rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm && \
yum -y install epel-release \
python-devel python-pip python-dev python-virtualenv zip \
wget bzip2 java-1.8.0-openjdk java-1.8.0-openjdk-devel tar unzip libXdmcp \
vi vim sudo yum-utils policycoreutils selinux-policy-targeted openssh && \
yum -y update && \
yum clean all
ENV JAVA_HOME=/usr/lib/jvm/java-1.8.0
RUN wget https://repo.continuum.io/archive/Anaconda3-4.2.0-Linux-x86_64.sh && \
bash Anaconda3-4.2.0-Linux-x86_64.sh -b -p /opt/anaconda3 && \
rm -f Anaconda3-4.2.0-Linux-x86_64.sh
ENV PATH="/opt/anaconda3/bin:$PATH"
# pip install python libraries
RUN ipython kernel install --user && \
pip install --upgrade pip && \
conda update setuptools && \
pip install docker kubernetes
RUN jupyter notebook --generate-config && \
ipython profile create
RUN echo "c.NotebookApp.ip = '*'" >>/root/.jupyter/jupyter_notebook_config.py && \
echo "c.NotebookApp.open_browser = False" >>/root/.jupyter/jupyter_notebook_config.py && \
echo "c.InteractiveShellApp.matplotlib = 'inline'" >>/root/.ipython/profile_default/ipython_config.py
EXPOSE 8888
WORKDIR /opt/
CMD ["jupyter", "notebook"]
启动一个能够操作Docker和Kubernetes的Docker容器。
我們將啟動使用上述所創建的Python客戶端的Docker映像。為了訪問主機上的DockerEngine,需要訪問主機OS上的/var/run/docker.sock。此外,為了訪問主機上的Kubernetes,需要訪問Kubernetes主控節點上的/root/.kube/目錄。因此,我們將使用-v選項將主機上的/var/run/docker.sock和/root/.kube/掛載到容器中。
docker run -it \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /root/.kube/:/root/.kube/ \
-v /opt/workdir:/opt/workdir \
-w="/opt/workdir/" \
-p 8888:8888 \
--name pdk \
pythoncli:1.0 \
/bin/bash
顺便将/opt/workdir/作为工作环境挂载起来。
使用/bin/bash启动只是为了确认挂载,不是必需的。
使用Docker的Python
我将在Docker上的Python中访问主机的Docker引擎。首先,我会在Python中导入docker,并配置Docker客户端。然后,我会尝试运行docker run hello-world。以下是Python代码的示例。
import docker
client = docker.from_env()
client.containers.run("hello-world")
使用Docker pull和Docker run命令来拉取并运行众所周知的Hello World。
接下来,我们试试从Dockerfile构建并启动容器。
Dockerfile的内容如下所示。
FROM ubuntu:16.04
MAINTAINER cvusk
RUN echo "test python client for docker" >> /tmp/test.log
CMD ["cat", "/tmp/test.log"]
我会编译并运行这个。
client.images.build(path="/opt/workdir/test", tag="ubuntu:test")
client.containers.run("ubuntu:test")
只要准备好Dockerfile,就可以简单地构建和启动映像。
当然,也可以通过Python从文本处理和文件操作生成Dockerfile,但这更偏向于文本处理的领域,而不是Docker的Python客户端。所以在这个例子中,我们将省略这部分内容。
DockerのPythonクライアントについて、詳しいドキュメントはこちらにありますので、ご参照ください。
http://docker-py.readthedocs.io/en/stable/index.html
使用Docker中的Python与Kubernetes交互
接下来,我们将使用Python来操作Kubernetes。
这次我们将在Kubernetes的Deployment中启动nginx,并通过Service进行公开。
Kubernetes的配置将通过yml文件来进行,我们将从Python生成yml文件,并启动Deployment和Service。
首先作为准备工作,导入Kubernetes,并加载/root/.kube/config以查看已启动的Pods的列表。
from kubernetes import client as kclient
from kubernetes import config as kconfig
import yaml
import os
kconfig.load_kube_config()
v1 = kclient.CoreV1Api()
print("Listing pods with their IPs:")
ret = v1.list_pod_for_all_namespaces(watch=False)
for i in ret.items:
print("%s\t%s\t%s" % (i.status.pod_ip, i.metadata.namespace, i.metadata.name))
只要显示如下,就可以了。
生成yml文件。
这将是用于nginx的Deployment和Service的yml文件,但首先需要使用Python的Dict进行定义,并将其转储。
nginxdep = {'apiVersion': 'extensions/v1beta1',
'kind': 'Deployment',
'metadata': {'name': 'my-nginx'},
'spec': {'replicas': 1,
'selector': {'matchLabels': {'run': 'my-nginx'}},
'template': {'metadata': {'labels': {'run': 'my-nginx'}},
'spec': {'containers': [{'image': 'nginx',
'name': 'my-nginx',
'ports': [{'containerPort': 80}]}]}}}}
nginxsvc = {'apiVersion': 'v1',
'kind': 'Service',
'metadata': {'labels': {'run': 'my-nginx'}, 'name': 'my-nginx'},
'spec': {'externalIPs': ['35.200.42.99'],
'ports': [{'nodePort': 30000, 'port': 80, 'protocol': 'TCP'}],
'selector': {'run': 'my-nginx'},
'type': 'LoadBalancer'}}
with open("kube/nginxdep.yml", "w") as f:
f.write(yaml.dump(nginxdep, default_flow_style=False))
with open("kube/nginxsvc.yml", "w") as f:
f.write(yaml.dump(nginxsvc, default_flow_style=False))
因为在Python中,我们使用Dict来定义yml,所以可以轻松地通过编程生成或修改它。
接下来将部署这个yml文件。
我已将一些易于使用的功能组合到一个方便使用的Class中,但请参考这里的所有功能。
class KubeDeployer(object):
def __init__(self):
kconfig.load_kube_config()
self.__k8s_beta = kclient.ExtensionsV1beta1Api()
self.__k8s_core = kclient.CoreV1Api()
def createDeployment(self, filename, filedir=None):
if filedir is not None:
filename = os.path.join(filedir, filename)
with open(filename) as f:
dep = yaml.load(f)
resp = self.__k8s_beta.create_namespaced_deployment(
body=dep, namespace="default")
print("DEPLOYMENT {0} created. status={1}".format(filename, resp.metadata))
return resp
def getDeploymentList(self):
resp = self.__k8s_beta.list_deployment_for_all_namespaces()
return resp
def deleteDeployment(self, name, namespace="default", **kwargs):
body = kubernetes.client.V1DeleteOptions(**kwargs)
resp = self.__k8s_beta.delete_namespaced_deployment(name, namespace, body, **kwargs)
return resp
def deleteAllDeployment(self, namespace="default", **kwargs):
respd = self.__k8s_beta.delete_collection_namespaced_deployment(namespace)
respr = self.__k8s_beta.delete_collection_namespaced_replica_set(namespace)
respp = self.__k8s_core.delete_collection_namespaced_pod(namespace)
return respd,respr,respp
def createService(self, filename, filedir=None):
if filedir is not None:
filename = os.path.join(filedir, filename)
with open(filename) as f:
svc = yaml.load(f)
resp = self.__k8s_core.create_namespaced_service(
body=svc, namespace="default")
print("SERVICE {0} created. status={1}".format(filename, resp.metadata))
return resp
def getServiceList(self):
resp = self.__k8s_core.list_service_for_all_namespaces()
return resp
def deleteService(self, name, namespace="default", **kwargs):
resp = self.__k8s_core.delete_namespaced_service(name, namespace, **kwargs)
return resp
# create deployment and service
kd = KubeDeployer()
kdeploy = kd.createDeployment("nginxdep.yml", "/opt/workdir/kube/")
ksvc = kd.createService("nginxsvc.yml", "/opt/workdir/kube/")
Nginx已经成功启动,并在30000端口上进行了公开。
KubernetesからKubernetesを使う
それでは最後にKubernetesからKubernetesを使います。
上記のようにDocker上のPythonからKubernetesを使えるので、KubernetesのPodsからホストOSのKubernetesにアクセスしてKubernetesを操作することも可能です。
这次我们将从Kubernetes的Job中启动nginx的Deployment和Service。
我们先定义Jobs如下。
cat <<- EOF > deployjob.yml
apiVersion: batch/v1
kind: Job
metadata:
name: deployer
spec:
template:
spec:
containers:
- name: deployer
image: pythoncli:1.0
command: ["python", "/opt/workdir/python_kube.py"]
workingDir: /opt/workdir/
volumeMounts:
- mountPath: /opt/workdir/
name: workdir
- mountPath: /bin/
name: kubectl
- mountPath: /root/.kube/
name: kubecfg
volumes:
- name: workdir
hostPath:
path: /opt/workdir/
- name: kubectl
hostPath:
path: /bin/
- name: kubecfg
hostPath:
path: /root/.kube/
restartPolicy: Never
backoffLimit: 4
EOF
Commandで実行するPythonスクリプトは以下のとおりですが、前項でDockerからKubernetesを起動したものとほぼ同じになります。
from kubernetes import client as kclient
from kubernetes import config as kconfig
import yaml
import os
nginxdep = {'apiVersion': 'extensions/v1beta1',
'kind': 'Deployment',
'metadata': {'name': 'my-nginx'},
'spec': {'replicas': 1,
'selector': {'matchLabels': {'run': 'my-nginx'}},
'template': {'metadata': {'labels': {'run': 'my-nginx'}},
'spec': {'containers': [{'image': 'nginx',
'name': 'my-nginx',
'ports': [{'containerPort': 80}]}]}}}}
nginxsvc = {'apiVersion': 'v1',
'kind': 'Service',
'metadata': {'labels': {'run': 'my-nginx'}, 'name': 'my-nginx'},
'spec': {'externalIPs': ['35.200.42.99'],
'ports': [{'nodePort': 30000, 'port': 80, 'protocol': 'TCP'}],
'selector': {'run': 'my-nginx'},
'type': 'LoadBalancer'}}
with open("kube/nginxdep.yml", "w") as f:
f.write(yaml.dump(nginxdep, default_flow_style=False))
with open("kube/nginxsvc.yml", "w") as f:
f.write(yaml.dump(nginxsvc, default_flow_style=False))
class KubeDeployer(object):
def __init__(self):
kconfig.load_kube_config()
self.__k8s_beta = kclient.ExtensionsV1beta1Api()
self.__k8s_core = kclient.CoreV1Api()
def createDeployment(self, filename, filedir=None):
if filedir is not None:
filename = os.path.join(filedir, filename)
with open(filename) as f:
dep = yaml.load(f)
resp = self.__k8s_beta.create_namespaced_deployment(
body=dep, namespace="default")
print("DEPLOYMENT {0} created. status={1}".format(filename, resp.metadata))
return resp
def getDeploymentList(self):
resp = self.__k8s_beta.list_deployment_for_all_namespaces()
return resp
def deleteDeployment(self, name, namespace="default", **kwargs):
body = kubernetes.client.V1DeleteOptions(**kwargs)
resp = self.__k8s_beta.delete_namespaced_deployment(name, namespace, body, **kwargs)
return resp
def deleteAllDeployment(self, namespace="default", **kwargs):
respd = self.__k8s_beta.delete_collection_namespaced_deployment(namespace)
respr = self.__k8s_beta.delete_collection_namespaced_replica_set(namespace)
respp = self.__k8s_core.delete_collection_namespaced_pod(namespace)
return respd,respr,respp
def createService(self, filename, filedir=None):
if filedir is not None:
filename = os.path.join(filedir, filename)
with open(filename) as f:
svc = yaml.load(f)
resp = self.__k8s_core.create_namespaced_service(
body=svc, namespace="default")
print("SERVICE {0} created. status={1}".format(filename, resp.metadata))
return resp
def getServiceList(self):
resp = self.__k8s_core.list_service_for_all_namespaces()
return resp
def deleteService(self, name, namespace="default", **kwargs):
resp = self.__k8s_core.delete_namespaced_service(name, namespace, **kwargs)
return resp
kd = KubeDeployer()
kdeploy = kd.createDeployment("nginxdep.yml", "/opt/workdir/kube/")
ksvc = kd.createService("nginxsvc.yml", "/opt/workdir/kube/")
それではKubernetesでJobsを起動します。
kubectl create -f deployjob.yml
首先,Kubernetes任务与Pod一起启动。
过一会儿,nginx的Deployment和Service将会启动。
Nginx已经成功启动并发布了。
最后一句话
我是用Python、Docker和Kubernetes来介绍了如何使用Docker和Kubernetes从Docker和Kubernetes中使用Kubernetes的方法。
个人而言,我希望在Kubernetes上进行基础设施即代码的管理(也希望将Kubernetes的管理集中在Kubernetes上),所以我进行了一些调查,结果出乎意外地顺利。
尽管Docker和Kubernetes都很复杂,但一旦熟悉就会觉得很有趣,对吧。
顺便说明一下,由于我们已经删除了这次部署的全部环境,希望没有带来任何不便。
请你提供以下内容的中文本地语言释义,只需要一个选项:
– 参考
https://github.com/kubernetes-client/python/blob/master/kubernetes/README.md 的内容
http://docker-py.readthedocs.io/en/stable/index.html