導入:
- コンテナーのデプロイメントにサーバーが関与する場合
多个节点
、docker と docker-compose を使用したデプロイメントはあまり便利ではありません。均一に制御できず、スケール、統合管理、バージョン管理の構成が不便です。ビジネスにクラスター コンテナーのデプロイメントが含まれる場合は、次のことを考慮する必要があります。 K8s、K3sが実装されています。
k8s アーキテクチャは次のもので構成されます。
- (1) マスター: apiserver、スケジューラー、コントローラーマネージャー、ETCD
- (複数) ノード: kubelet、kube-proxy、コンテナ エンジン (containerd、docker)
APIサーバーの場合:
- kubernetes API を公開するために使用され、リソースのリクエストまたは呼び出し操作は、kube-apiserver によって提供されるインターフェイスを通じて実行されます。HTTP Restful API はインターフェイス サービスを提供するために使用され、オブジェクト リソースのすべての追加、削除、変更、クエリ、監視操作は API サーバーに渡されて処理され、Etcd ストレージに送信されます。
API Server は K8S のリクエストエントリサービスであることがわかります。API サーバーは、(UI インターフェイスまたは CLI コマンド ライン ツールから) すべての K8S リクエストを受信し、ユーザーの特定のリクエストに従って動作するように他のコンポーネントに通知する責任があります。API サーバーは、K8S クラスター アーキテクチャの頭脳であると言えます。
Kube-コントローラー-マネージャー:
- 運用管理制御は、K8S クラスタ内の通常のタスクを処理するバックグラウンド スレッドであり、K8S クラスタ内のすべてのリソース オブジェクトの自動制御センターです。
K8S クラスターでは、1 つのリソースがコントローラーに対応し、コントローラー マネージャーがこれらのコントローラーを管理します。これは、API サーバーを通じてクラスター全体のステータスを監視し、クラスターが期待どおりの動作状態にあることを確認する一連のコントローラーで構成されています。たとえば、ノードが予期せずクラッシュした場合、コントローラー マネージャーは即座に自動化されたエラーを検出して実行します。クラスタが常に良好な状態にあることを確認するための修復プロセス。期待される動作状態。
kubeスケジューラ:
- リソースのスケジューリングを担当するプロセスは、スケジューリング アルゴリズムに従って、新しく作成された Pod に適切な Node ノードを選択します。これは、すべての K8S Node ノードのスケジューラとして理解できます。サービスのデプロイに使用される場合、スケジューラは、スケジューリング アルゴリズムに基づいてポッドをデプロイするために最も適切なノードを選択します。
etcd 構成ストレージ センター:
- 8Sストレージサービス。etcd 分散キー/値ストレージ システムには、K8S のキー構成とユーザー構成が保存されます。K8S の API サーバーのみが読み取りおよび書き込み権限を持ちます。他のコンポーネントは、API サーバー インターフェイスを介してデータの読み取りおよび書き込みを行う必要があります。
キュベレット:
- Node ノードの監視者および Master ノードとの通信者。Kubelet は、ノード ノードにインストールされたマスター ノードの「アイライナー」であり、ノード ノードで実行されているサービスのステータスを API サーバーに定期的に報告し、マスター ノードからの指示を受け入れて調整措置を講じます。
マスターノードから自身のノード上のポッドの予期されるステータス(実行するコンテナ、実行中のレプリカの数、ネットワークやストレージの構成方法など)を取得し、コンテナエンジンと直接対話して実装します。コンテナのライフサイクル管理自身のノード上のポッドのステータスが異なる場合、期待される状態に一貫性がない場合は、対応するコンテナ プラットフォーム インターフェイス (つまり、Docker インターフェイス) を呼び出してこの状態に到達します。イメージとコンテナのクリーンアップを管理して、ノード上のイメージがディスク領域全体を占有しないように、また、終了したコンテナが多くのリソースを占有しないようにします。
代理の場合:
- ポッド ネットワーク エージェントは各ノード ノードに実装されており、Kuberbetes サービス リソースのキャリアであり、ネットワーク プランニングと 4 層のロード バランシングの維持を担当します。サービス マッピング アクセスを実装するための iptables および ipvs へのルールの作成を担当します。
Kube-Proxy 自体は Pod に直接ネットワークを提供するのではなく、Pod のネットワークは Kubelet によって提供され、実際には仮想 Pod クラスター ネットワークを維持します。
Kube-apiserver は、Kube-Proxy を監視することで Kubernets Service を更新し、エンドポイントを維持します。
Kube-Proxy は、K8S クラスター内のロード バランサーです。これは、K8S の各ノードで Kube プロキシを実行する分散プロキシ サーバーです。
ポッド:
- 1. ポッドは、Kuberntes によって作成またはデプロイされる最小/単純な基本単位であり、クラスター上で実行されているプロセスを表します。ポッドはエンドウ豆のさやとして理解でき、同じポッド内の各コンテナはエンドウ豆です。
2. ポッドは 1 つ以上のコンテナで構成され、ポッド内のコンテナはネットワーク、ストレージ、コンピューティング リソースを共有し、同じ Docker ホスト上で実行されます。
3. 複数のコンテナを Pod 内で実行できます。これは SideCara モードとも呼ばれます。実稼働環境では、単一のコンテナー、または強い相関性と相補性を持つ複数のコンテナーでポッドを形成します。
4. 同じポッド間のコンテナはローカルホスト経由で相互にアクセスでき、ポッド内のすべてのデータ ボリュームをマウントできますが、異なるポッド間のコンテナはローカルホスト経由でアクセスしたり、他のポッドのデータ ボリュームをマウントしたりすることはできません。
よく使用されるコマンド:
#获取默认 命名空间pod列表
kubectl get pod
#获取 pod详情包含部署节点、容器ID
kubectl get pod -o wide
#删除指定pod -默认命名空间
kubectl delete pod test-pod
#查询 pod进程描述 xx -pod名称
kubectl describe pod xx
#查询 xx pod日志信息
kubectl logs xx
#查询 xx pod日志信息 持续输出
kubectl logs xx -f
#指定命名空间,查看pod 日志
kubectl logs device-info-868fddfc54-p2cd7 -f -n xiaoshu
# 进入某 xx pod容器内部
kubectl exec -it xx -- bash
#指定命名空间,进去容器内部
kubectl exec -it device-info-868fddfc54-p2cd7 -n xiaoshu -- bash
# 部署yml到指定的命名空间
kubectl apply -f app.yml --namespace testapp
# 获取pod列表 指定命令空间
kubectl get pod -n kube-system
# pod 零时端口映射
kubectl port-forward xx 8080:8080
# 获取默认空间 副本集列表
kubectl get deployment
# 获取默认空间 有状态应用集列表
kubectl get StatefulSet
# 删除 test-k8s 名称副本集
kubectl delete deployment test-k8s
# 调整 xx 副本数量
kubectl scale deployment xx --replicas=10
# 查询 xx 副本集,部署历史
kubectl rollout history deployment xx
# 回退上个版本
ubectl rollout undo deployment test-k8s
# 回退指定版本
kubectl rollout undo deployment test-k8s --to-revision=2
# 查看全部
kubectl get all
# 重新部署
kubectl rollout restart deployment test-k8s
# 命令修改镜像,--record 表示把这个命令记录到操作历史中
kubectl set image deployment test-k8s test-k8s=ccr.ccs.tencentyun.com/k8s-tutorial/test-k8s:v2-with-error --record
# 暂停运行,暂停后,对 deployment 的修改不会立刻生效,恢复后才应用设置
kubectl rollout pause deployment test-k8s
# 恢复
kubectl rollout resume deployment test-k8s
# 输出到文件
kubectl get deployment test-k8s -o yaml >> app2.yaml
# 删除全部资源
kubectl delete all --all
kubectl delete all --all -n xiaoshu
# 挂载数据集相关
# 先删除pod再删除pvc最后删除pv
kubectl get pv -n xxx
kubectl get pvc -n xxx
# 简写:cm
# 应用
kubectl apply -f configmap.yaml
# 查看
kubectl get configmap mongo-config -o yaml
#挂载配置文件
kubectl create configmap [configmap名称] --from-file=[文件]
# crictl -k8s中CRI(容器运行时接口)的客户端
crictl images
# containerd
ctr images import xx.tar
# -- 指定导入:
ctr --namespace k8s.io image import xx.tar
ctr images list|grep xx
Javaクライアントがk8s APIサーバーに接続します
- 構成
admin token
- io.kubernetes-client-java の紹介
- 民間の倉庫港を建設する
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java</artifactId>
<version>17.0.0</version>
</dependency>
クライアントを初期化する
@Slf4j
@Component
public class K8sApiConfig {
@Resource
private VirtualProperties virtualProperties;
@Bean
public ApiClient k8sClient(){
ApiClient client = new ClientBuilder().
setBasePath(virtualProperties.getK8sUrl()).setVerifyingSsl(false).
setAuthentication(new AccessTokenAuthentication(virtualProperties.getK8sToken())).build();
Configuration.setDefaultApiClient(client);
return client;
}
}
virtual:
docker-url: tcp://192.168.2.207:8088
k8s-url: https://192.168.2.207:6443
k8s-token: xx
server-url: 192.168.2.207
server-name: root
server-pwd: 123456
tar-path: /opt/tar/
harbor-url: core.harbor.domain
harbor-uname: admin
harbor-pwd: Harbor12345
管理トークン yml を構成する
#部署 admin-token
kubectl apply -f k8s-admin.yaml
#查询 dashboard-admin开头secret
kubectl get secret -n kube-system|grep dashboard-admin
#查询 token
kubectl describe secret dashboard-admin-token-xx -n kube-system
apiVersion: v1
kind: ServiceAccount
metadata:
name: dashboard-admin
namespace: kube-system
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
name: dashboard-admin
subjects:
- kind: ServiceAccount
name: dashboard-admin
namespace: kube-system
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
API関連のコード
- vo オブジェクトのカプセル化は多すぎるため、ここではリストしませんが、
service
参考までにいくつか挙げておきます。
public interface K8sService {
/**
* 集群节点信息获取
* @return List<ClusterInfoVo>
*/
List<ClusterInfoVo> clusterInfo();
/**
* 导入镜像包
* @param file tar文件
* @return Boolead
*/
R<String> importTar(MultipartFile file);
/**
* k8s 镜像列表查询
* @param name 镜像名称
* @return
*/
List<String> k8sImages(String name);
/**
* 命名空间列表
* @return List<NameSpaceVo>
*/
List<NameSpaceVo> nameSpaces();
/**
* 部署副本集
* @param deploymentAddVo 副本集参数
* @return Boolean
*/
Boolean applyDeployment(DeploymentAddVo deploymentAddVo);
/**
* 部署状态应用副本集
* @param statefulSetAddVo 参数
* @return Boolean
*/
Boolean applyStatefulSet(StatefulSetAddVo statefulSetAddVo);
/**
* 副本集列表
* @param nameSpace 命令空间
* @return List<DeploymentVo>
*/
List<DeploymentVo> deployments(String nameSpace);
/**
* 挂载数据卷查询
* @param nameSpace 命名空间
*/
List<VolumesPvVo> volumes(String nameSpace);
/**
* 数据集申请单查询
*/
List<VolumesPvClaimVo> volumesClaim(String nameSpace);
/**
* 添加-挂载数据卷申请单
* @param volumesAddVo 数据集参数
*/
Boolean addVolumesClaim(VolumesAddVo volumesAddVo);
/**
* 添加-挂载数据卷
* @param volumesAddVo 数据集参数
*/
Boolean addVolumes(VolumesAddVo volumesAddVo);
/**
* 服务列表
* @param nameSpace 命令空间
* @return List<ServiceAddVo>
*/
List<ServiceAddVo> services(String nameSpace);
/**
* 服务部署
* @param serviceAddVo 服务创建参数
* @return Boolean
*/
Boolean applyService(ServiceAddVo serviceAddVo);
/**
* 删除服务
* @param deleteK8sVo
* @return
*/
Boolean deleteService(DeleteK8sVo deleteK8sVo);
/**
* 删除副本集
* @param deleteK8sVo
* @return
*/
Boolean deleteDeployment(DeleteK8sVo deleteK8sVo);
/**
* 创建configMap
* @return Boolean
*/
Boolean addConfigMap( ConfigMapVo configMapVo);
}
@Slf4j
@Service
public class K8sServiceImpl implements K8sService {
@Resource
private VirtualProperties virtualProperties;
@Override
public List<ClusterInfoVo> clusterInfo() {
CoreV1Api api = new CoreV1Api();
GenericKubernetesApi<NodeMetrics, NodeMetricsList> nodeMetricsListGenericKubernetesApi = new GenericKubernetesApi<>(
NodeMetrics.class,
NodeMetricsList.class,
"metrics.k8s.io",
"v1beta1",
"nodes",
api.getApiClient());
NodeMetricsList nodeMetricsList = nodeMetricsListGenericKubernetesApi.list().getObject();
HashMap<String, Map<String, String>> usages = new HashMap<>();
for (NodeMetrics item : nodeMetricsList.getItems()) {
String name = item.getMetadata().getName();
Map<String, Quantity> usage = item.getUsage();
Map<String, String> quantity = new HashMap<>();
for (String s : usage.keySet()) {
Quantity quantity1 = usage.get(s);
if (s.equals("cpu")){
String cpu = quantity1.toSuffixedString().replace("n","");
double v = NumberUtil.div(Long.parseLong(cpu), 1000_000_000, 2);
quantity.put(s,String.valueOf(v));
}else {
long curByte = quantity1.getNumber().longValue();
quantity.put(s,String.valueOf(curByte));
}
}
usages.put(name,quantity);
}
List<ClusterInfoVo> clusterInfoVos = new LinkedList<>();
try {
V1NodeList nodeList = api.listNode("true", false, null, null, null, null, null, null, 60, false);
List<V1Node> items = nodeList.getItems();
for (V1Node node : items) {
ClusterInfoVo clusterInfoVo = new ClusterInfoVo();
V1NodeStatus nodeStatus = node.getStatus();
//节点镜像列表
List<V1ContainerImage> images = nodeStatus.getImages();
List<V1NodeAddress> addresses = nodeStatus.getAddresses();
//node节点ip地址
String nodeIp = addresses.get(0).getAddress();
clusterInfoVo.setClusterId(nodeIp);
String hostName = addresses.get(1).getAddress();
clusterInfoVo.setNodeName(hostName);
//容量信息
Map<String, Quantity> capacity = nodeStatus.getCapacity();
capacity.forEach((k,v)->{
//cpu 核数
if (k.equals("cpu")){
BigDecimal cpu = v.getNumber();
Long totalCpu = cpu.longValue();
clusterInfoVo.setCpuCores(cpu.intValue());
if(usages.get(hostName)!=null){
String useCpu = usages.get(hostName).get("cpu");
clusterInfoVo.setCpuUses(useCpu);
double v1 = NumberUtil.div(Double.valueOf(useCpu).doubleValue(), totalCpu.doubleValue(), 2);
BigDecimal scale = new BigDecimal(v1).multiply(new BigDecimal(100)).setScale(0, RoundingMode.HALF_UP);
clusterInfoVo.setCpuPercent(scale.toString());
clusterInfoVo.setOnlineStatus(Boolean.TRUE);
}else {
clusterInfoVo.setOnlineStatus(Boolean.FALSE);
}
}
//临时存储
if (k.equals("ephemeral-storage")){
BigDecimal ephemeral = v.getNumber();
clusterInfoVo.setDiskSize(LocalFileUtil.fileShow(ephemeral.longValue()));
}
//内存
if (k.equals("memory")){
BigDecimal memory = v.getNumber();
long totalMemory = memory.longValue();
clusterInfoVo.setMemory(LocalFileUtil.fileShow(totalMemory));
if (usages.get(hostName)!=null){
Long useMemory = Long.parseLong(usages.get(hostName).get("memory"));
clusterInfoVo.setUserMemory(LocalFileUtil.fileShow(useMemory));
double v1 = NumberUtil.div(useMemory.longValue(), totalMemory, 2);
BigDecimal scale = new BigDecimal(v1).multiply(new BigDecimal(100)).setScale(0, RoundingMode.HALF_UP);
clusterInfoVo.setMemoryPercent(scale.toString());
}
}
//运行容器数
if (k.equals("pod")){
BigDecimal pods = v.getNumber();
clusterInfoVo.setPods(pods.intValue());
}
});
V1NodeSystemInfo nodeInfo = nodeStatus.getNodeInfo();
//处理器
String architecture = nodeInfo.getArchitecture();
clusterInfoVo.setArchitecture(architecture);
//机器编号
String machineID = nodeInfo.getMachineID();
clusterInfoVo.setMachineID(machineID);
//操作系统
String operatingSystem = nodeInfo.getOperatingSystem();
clusterInfoVo.setOperatingSystem(operatingSystem);
//系统镜像
String osImage = nodeInfo.getOsImage();
clusterInfoVo.setOsImage(osImage);
V1ObjectMeta metadata = node.getMetadata();
OffsetDateTime dateTime = metadata.getCreationTimestamp();
Date date = Date.from(dateTime.toLocalDateTime().toInstant(ZoneOffset.ofHours(8)));
clusterInfoVo.setCreateTime(date);
clusterInfoVos.add(clusterInfoVo);
}
} catch (ApiException e) {
e.printStackTrace();
}
return clusterInfoVos;
}
@Override
public R<String> importTar(MultipartFile file) {
long size = file.getSize();
if (size==0){
return R.failed("不能上传空文件");
}
long fileName = IdUtil.getSnowflakeNextId();
String originalFilename = file.getOriginalFilename();
log.info("originalFilename:"+originalFilename);
String suffix = FileUtil.getSuffix(originalFilename);
log.info("suffix:"+suffix);
if (!"tar".equals(suffix)){
return R.failed("请上传镜像文件tar包");
}
try {
String tarName = fileName +"."+ suffix;
File tarFile = new File(virtualProperties.getTarPath() + tarName);
file.transferTo(tarFile);
if (tarFile.exists()){
log.info("tarName:"+tarName);
List<String> resMsg = ExecUtil.remoteExec("ctr --namespace k8s.io image import "+virtualProperties.getTarPath()+ tarName,
virtualProperties.getServerUrl(),
virtualProperties.getServerName(), virtualProperties.getServerPwd());
boolean done = resMsg.stream().allMatch(e -> e.contains("done"));
if (done){
return R.ok("上传成功");
}else {
return R.failed("上传失败");
}
}else {
return R.failed("上传失败");
}
} catch (IOException e) {
e.printStackTrace();
return R.failed("上传失败");
}
}
@Override
public List<String> k8sImages(String name) {
//V1Node status = api.re(node.getMetadata().getName(), "true");
List<String> resMsg = new LinkedList<>();
try {
String cmd="crictl images";
if (StrUtil.isNotEmpty(name)){
cmd=cmd+"|grep "+name;
}
resMsg = ExecUtil.remoteExec(cmd,virtualProperties.getServerUrl(),
virtualProperties.getServerName(), virtualProperties.getServerPwd());
} catch (IOException e) {
e.printStackTrace();
}
return resMsg;
}
@Override
public List<NameSpaceVo> nameSpaces() {
List<NameSpaceVo> res = new LinkedList<>();
CoreV1Api api = new CoreV1Api();
V1NamespaceList listNamespace = null;
try {
listNamespace = api.listNamespace("true", null, null, null, null, null, null, null, null, false);
} catch (ApiException e) {
e.printStackTrace();
}
if (listNamespace==null){
return res;
}
List<V1Namespace> items = listNamespace.getItems();
items.forEach(e->{
NameSpaceVo nameSpaceVo = new NameSpaceVo();
String status = e.getStatus().getPhase();
nameSpaceVo.setStatus(status);
V1ObjectMeta meta = e.getMetadata();
String name = meta.getName();
nameSpaceVo.setName(name);
OffsetDateTime dateTime = meta.getCreationTimestamp();
Date date = Date.from(dateTime.toLocalDateTime().toInstant(ZoneOffset.ofHours(8)));
nameSpaceVo.setCreateTime(date);
res.add(nameSpaceVo);
});
return res;
}
@Override
public Boolean applyDeployment(DeploymentAddVo deploymentAddVo) {
AppsV1Api api = new AppsV1Api();
V1ObjectMeta meta = new V1ObjectMeta();
if (StrUtil.isEmpty(deploymentAddVo.getName())){
log.info("副本集名称不能为空");
return Boolean.FALSE;
}
if (StrUtil.isEmpty(deploymentAddVo.getNameSpace())){
log.info("需要指定命名空间");
return Boolean.FALSE;
}
meta.setName(deploymentAddVo.getName());
meta.setNamespace(deploymentAddVo.getNameSpace());
List<LabelsOrKvVo> labelVo = deploymentAddVo.getLabels();
if (CollectionUtil.isEmpty(labelVo)){
log.info("至少需要输入一个标签");
return Boolean.FALSE;
}
Map<String,String> labels = new HashMap<>(labelVo.size());
for (LabelsOrKvVo labelsOrKvVo : labelVo) {
labels.put(labelsOrKvVo.getKey(), labelsOrKvVo.getValue());
}
meta.setLabels(labels);
V1Deployment v1Deployment = new V1Deployment();
v1Deployment.setMetadata(meta);
v1Deployment.setKind("Deployment");
v1Deployment.setApiVersion(deploymentAddVo.getVersion());
V1DeploymentSpec deploymentSpec = new V1DeploymentSpec();
if (deploymentAddVo.getReplicas()==null){
deploymentAddVo.setReplicas(1);
}
deploymentSpec.setReplicas(deploymentAddVo.getReplicas());
V1LabelSelector selector = new V1LabelSelector();
selector.setMatchLabels(labels);
deploymentSpec.setSelector(selector);
V1PodTemplateSpec templateSpec = new V1PodTemplateSpec();
V1ObjectMeta v1ObjectMeta = new V1ObjectMeta();
v1ObjectMeta.setLabels(labels);
templateSpec.setMetadata(v1ObjectMeta);
V1PodSpec v1PodSpec = new V1PodSpec();
//set containers
List<ContainerVo> containerVos = deploymentAddVo.getContainers();
if (CollectionUtil.isEmpty(containerVos)){
log.info("副本集镜像列表不能为空");
return Boolean.FALSE;
}
List<V1Container> containers = new LinkedList<>();
for (ContainerVo containerVo : containerVos) {
//set volumes
if (CollectionUtil.isNotEmpty(containerVo.getHostPath())){
List<V1Volume> volumes = new LinkedList<>();
List<ClaimHostVo> hostPaths = containerVo.getHostPath();
for (ClaimHostVo path : hostPaths) {
V1Volume v1Volume = new V1Volume();
V1HostPathVolumeSource hostPathVolumeSource = new V1HostPathVolumeSource();
hostPathVolumeSource.setType(path.getType());
hostPathVolumeSource.setPath(path.getHostPath());
v1Volume.setHostPath(hostPathVolumeSource);
v1Volume.setName(path.getVolumeClaim());
volumes.add(v1Volume);
}
v1PodSpec.setVolumes(volumes);
}
V1Container v1Container = new V1Container();
v1Container.setName(containerVo.getName());
if (!containerVo.getImage().contains(":")){
log.info("镜像地址需要携带版本号");
return Boolean.FALSE;
}
v1Container.setImage(containerVo.getImage());
v1Container.setImagePullPolicy(containerVo.getImagePullPolicy());
if (CollectionUtil.isNotEmpty(containerVo.getHostPath())){
List<V1VolumeMount> volumeMounts = new LinkedList<>();
List<ClaimMountVo> mountPath = containerVo.getMountPath();
for (ClaimMountVo path : mountPath) {
V1VolumeMount volumeMount = new V1VolumeMount();
volumeMount.setName(path.getVolumeClaim());
volumeMount.setMountPath(path.getMountPath());
volumeMounts.add(volumeMount);
}
v1Container.setVolumeMounts(volumeMounts);
}
V1EnvFromSource envFromSource = new V1EnvFromSource();
if (StrUtil.isNotEmpty(deploymentAddVo.getConfigMap())){
envFromSource.setConfigMapRef(new V1ConfigMapEnvSource().name(deploymentAddVo.getConfigMap()));
v1Container.setEnvFrom(Collections.singletonList(envFromSource));
}
containers.add(v1Container);
}
v1PodSpec.setContainers(containers);
//指定节点名称部署
String nodeName = deploymentAddVo.getNodeName();
if (StrUtil.isNotEmpty(nodeName)){
v1PodSpec.setNodeName(nodeName);
}
templateSpec.setSpec(v1PodSpec);
deploymentSpec.template(templateSpec);
v1Deployment.setSpec(deploymentSpec);
try {
api.createNamespacedDeployment(deploymentAddVo.getNameSpace(), v1Deployment, "true", null, null, null);
return Boolean.TRUE;
}catch (ApiException e){
log.error("副本集deployment部署失败");
log.error("Status code: {}", e.getCode());
log.error("Reason: {}", e.getResponseBody());
return Boolean.FALSE;
}
}
@Override
public Boolean applyStatefulSet(StatefulSetAddVo statefulSetAddVo) {
AppsV1Api api = new AppsV1Api();
V1StatefulSet statefulSet = new V1StatefulSet();
statefulSet.setKind("StatefulSet");
V1ObjectMeta meta = new V1ObjectMeta();
if (StrUtil.isEmpty(statefulSetAddVo.getName())){
log.info("状态副本集名称不能为空");
return Boolean.FALSE;
}
if (StrUtil.isEmpty(statefulSetAddVo.getNameSpace())){
log.info("需要指定命名空间");
return Boolean.FALSE;
}
meta.setName(statefulSetAddVo.getName());
meta.setNamespace(statefulSetAddVo.getNameSpace());
List<LabelsOrKvVo> labelVo = statefulSetAddVo.getLabels();
if (CollectionUtil.isEmpty(labelVo)){
log.info("至少需要输入一个标签");
return Boolean.FALSE;
}
Map<String,String> labels = new HashMap<>(labelVo.size());
for (LabelsOrKvVo labelsOrKvVo : labelVo) {
labels.put(labelsOrKvVo.getKey(), labelsOrKvVo.getValue());
}
meta.setLabels(labels);
statefulSet.setMetadata(meta);
V1StatefulSetSpec spec = new V1StatefulSetSpec();
if (statefulSetAddVo.getReplicas()==null){
statefulSetAddVo.setReplicas(1);
}
spec.setReplicas(statefulSetAddVo.getReplicas());
V1LabelSelector selector = new V1LabelSelector();
selector.setMatchLabels(labels);
spec.setSelector(selector);
spec.setServiceName(statefulSetAddVo.getName());
V1PodTemplateSpec templateSpec = new V1PodTemplateSpec();
V1ObjectMeta v1ObjectMeta = new V1ObjectMeta();
v1ObjectMeta.setLabels(labels);
templateSpec.setMetadata(v1ObjectMeta);
V1PodSpec v1PodSpec = new V1PodSpec();
//set containers
List<ContainerVo> containerVos = statefulSetAddVo.getContainers();
if (CollectionUtil.isEmpty(containerVos)){
log.info("副本集镜像列表不能为空");
return Boolean.FALSE;
}
List<V1Container> containers = new LinkedList<>();
for (ContainerVo containerVo : containerVos) {
//set volumes
if (CollectionUtil.isNotEmpty(containerVo.getHostPath())){
List<V1Volume> volumes = new LinkedList<>();
List<ClaimHostVo> hostPaths = containerVo.getHostPath();
for (ClaimHostVo path : hostPaths) {
V1Volume v1Volume = new V1Volume();
V1HostPathVolumeSource hostPathVolumeSource = new V1HostPathVolumeSource();
hostPathVolumeSource.setType(path.getType());
hostPathVolumeSource.setPath(path.getHostPath());
v1Volume.setHostPath(hostPathVolumeSource);
v1Volume.setName(path.getVolumeClaim());
volumes.add(v1Volume);
}
v1PodSpec.setVolumes(volumes);
}
V1Container v1Container = new V1Container();
v1Container.setName(containerVo.getName());
if (!containerVo.getImage().contains(":")){
log.info("镜像地址需要携带版本号");
return Boolean.FALSE;
}
v1Container.setImage(containerVo.getImage());
v1Container.setImagePullPolicy(containerVo.getImagePullPolicy());
if (CollectionUtil.isNotEmpty(containerVo.getHostPath())){
List<V1VolumeMount> volumeMounts = new LinkedList<>();
List<ClaimMountVo> mountPath = containerVo.getMountPath();
for (ClaimMountVo path : mountPath) {
V1VolumeMount volumeMount = new V1VolumeMount();
volumeMount.setName(path.getVolumeClaim());
volumeMount.setMountPath(path.getMountPath());
volumeMounts.add(volumeMount);
}
v1Container.setVolumeMounts(volumeMounts);
}
V1EnvFromSource envFromSource = new V1EnvFromSource();
if (StrUtil.isNotEmpty(statefulSetAddVo.getConfigMap())){
envFromSource.setConfigMapRef(new V1ConfigMapEnvSource().name(statefulSetAddVo.getConfigMap()));
v1Container.setEnvFrom(Collections.singletonList(envFromSource));
}
containers.add(v1Container);
}
v1PodSpec.setContainers(containers);
//指定节点名称部署
String nodeName = statefulSetAddVo.getNodeName();
if (StrUtil.isNotEmpty(nodeName)){
v1PodSpec.setNodeName(nodeName);
}
templateSpec.setSpec(v1PodSpec);
spec.setTemplate(templateSpec);
statefulSet.setSpec(spec);
try {
api.createNamespacedStatefulSet(statefulSetAddVo.getNameSpace(),statefulSet,"true",null,null,null);
} catch (ApiException e) {
log.error("状态副本集StatefulSet部署失败");
log.error("Status code: {}", e.getCode());
log.error("Reason: {}", e.getResponseBody());
return Boolean.FALSE;
}
return Boolean.TRUE;
}
@Override
public List<DeploymentVo> deployments(String nameSpace) {
List<DeploymentVo> deploymentVos = new LinkedList<>();
AppsV1Api api = new AppsV1Api();
V1DeploymentList deployment;
try {
deployment = api.listNamespacedDeployment("xiaoshu","ture", false, null, null, null, 60, null,
null, 60, false);
} catch (ApiException e) {
e.printStackTrace();
return deploymentVos;
}
if (deployment==null){
return deploymentVos;
}
List<V1Deployment> items = deployment.getItems();
if (CollectionUtil.isNotEmpty(items)){
items.forEach(e->{
V1DeploymentStatus status = e.getStatus();
Integer readyReplicas = status.getReadyReplicas();
Integer availableReplicas = status.getAvailableReplicas();
String curStatus="期望副本数:"+readyReplicas+"实际副本数:"+availableReplicas;
DeploymentVo deploymentVo = new DeploymentVo();
deploymentVo.setStatus(curStatus);
V1ObjectMeta metadata = e.getMetadata();
String name = metadata.getName();
deploymentVo.setName(name);
OffsetDateTime dateTime = metadata.getCreationTimestamp();
Date date = Date.from(dateTime.toLocalDateTime().toInstant(ZoneOffset.ofHours(8)));
deploymentVo.setCreateTime(date);
V1DeploymentSpec spec = e.getSpec();
Integer replicas = spec.getReplicas();
deploymentVo.setReplicas(replicas);
V1PodTemplateSpec template = spec.getTemplate();
List<V1Container> containers = template.getSpec().getContainers();
List<ContainerVo> containerVos = new LinkedList<>();
containers.forEach(c->{
ContainerVo containerVo = new ContainerVo();
String containerName = c.getName();
containerVo.setName(containerName);
String image = c.getImage();
containerVo.setImage(image);
String imagePullPolicy = c.getImagePullPolicy();
containerVo.setImagePullPolicy(imagePullPolicy);
containerVos.add(containerVo);
});
deploymentVo.setContainers(containerVos);
deploymentVos.add(deploymentVo);
});
}
return deploymentVos;
}
@Override
public List<VolumesPvVo> volumes(String nameSpace) {
List<VolumesPvVo> res = new LinkedList<>();
CoreV1Api api = new CoreV1Api();
V1PersistentVolumeList pvList = null;
try {
pvList = api.listPersistentVolume("true",false,null,null,null,null,null,null,60,false);
List<V1PersistentVolume> items = pvList.getItems();
if (CollectionUtil.isNotEmpty(items)){
items.forEach(e->{
VolumesPvVo volumesPvVo = new VolumesPvVo();
volumesPvVo.setName(e.getMetadata().getName());
V1PersistentVolumeSpec spec = e.getSpec();
volumesPvVo.setHostPath(spec.getHostPath().getPath());
volumesPvVo.setHostPathType(spec.getHostPath().getType());
volumesPvVo.setCapacity(LocalFileUtil.fileShow(spec.getCapacity().get("storage").getNumber().longValue()));
volumesPvVo.setVolumeMode(spec.getVolumeMode());
volumesPvVo.setStorageClassName(spec.getStorageClassName());
volumesPvVo.setAccessModes(spec.getAccessModes().get(0));
OffsetDateTime dateTime = e.getMetadata().getCreationTimestamp();
Date date = Date.from(dateTime.toLocalDateTime().toInstant(ZoneOffset.ofHours(8)));
volumesPvVo.setCreateTime(date);
volumesPvVo.setPersistentVolumeReclaimPolicy(spec.getPersistentVolumeReclaimPolicy());
volumesPvVo.setStatus(e.getStatus().getPhase());
res.add(volumesPvVo);
});
}
} catch (ApiException e) {
System.err.println("Exception when calling CoreV1Api#listPersistentVolume");
e.printStackTrace();
}
return res;
}
@Override
public List<VolumesPvClaimVo> volumesClaim(String nameSpace) {
List<VolumesPvClaimVo> res = new LinkedList<>();
CoreV1Api api = new CoreV1Api();
try {
V1PersistentVolumeClaimList persistentVolumeClaim = api.listNamespacedPersistentVolumeClaim(nameSpace, "true", false, null, null, null,
null, null, null, 60, false);
List<V1PersistentVolumeClaim> items = persistentVolumeClaim.getItems();
if (CollectionUtil.isNotEmpty(items)){
items.forEach(e->{
VolumesPvClaimVo pvClaimVo = new VolumesPvClaimVo();
pvClaimVo.setClaimName(e.getMetadata().getName());
pvClaimVo.setNameSpace(e.getMetadata().getNamespace());
OffsetDateTime dateTime = e.getMetadata().getCreationTimestamp();
Date date = Date.from(dateTime.toLocalDateTime().toInstant(ZoneOffset.ofHours(8)));
pvClaimVo.setCreateTime(date);
V1PersistentVolumeClaimSpec spec = e.getSpec();
pvClaimVo.setName(spec.getVolumeName());
pvClaimVo.setAccessModes(spec.getAccessModes().get(0));
pvClaimVo.setStorageClassName(spec.getStorageClassName());
pvClaimVo.setVolumeMode(spec.getVolumeMode());
V1PersistentVolumeClaimStatus status = e.getStatus();
pvClaimVo.setCapacity(LocalFileUtil.fileShow(status.getCapacity().get("storage").getNumber().longValue()));
pvClaimVo.setStatus(status.getPhase());
res.add(pvClaimVo);
});
}
} catch (ApiException e) {
e.printStackTrace();
}
return res;
}
@Override
public Boolean addVolumesClaim(VolumesAddVo volumesAddVo) {
CoreV1Api api = new CoreV1Api();
V1PersistentVolumeClaim pvc = new V1PersistentVolumeClaim();
// Set the metadata for the PVC
V1ObjectMeta meta = new V1ObjectMeta();
meta.setName(volumesAddVo.getClaimName());
meta.setNamespace(volumesAddVo.getNameSpace());
pvc.setMetadata(meta);
pvc.setKind("PersistentVolumeClaim");
// Set the spec for the PVC
V1PersistentVolumeClaimSpec spec = new V1PersistentVolumeClaimSpec();
//配置容量
Quantity quantity = new Quantity(volumesAddVo.getCapacity());
V1ResourceRequirements resources = new V1ResourceRequirements();
resources.putRequestsItem("storage",quantity);
spec.setResources(resources);
//配置访问模式
List<String> accessModes = new LinkedList<>();
accessModes.add(volumesAddVo.getAccessModes());
spec.setAccessModes(accessModes);
//..
spec.setVolumeMode(volumesAddVo.getVolumeMode());
spec.setStorageClassName(volumesAddVo.getStorageClassName());
spec.setVolumeName(volumesAddVo.getName());
pvc.setSpec(spec);
try {
api.createNamespacedPersistentVolumeClaim(volumesAddVo.getNameSpace(), pvc, "true", null, null,null);
} catch (ApiException e) {
log.error("数据卷申请单PVC创建失败");
log.error("Status code: {}", e.getCode());
log.error("Reason: {}", e.getResponseBody());
return Boolean.FALSE;
}
return Boolean.TRUE;
}
@Override
public Boolean addVolumes(VolumesAddVo volumesAddVo) {
CoreV1Api api = new CoreV1Api();
V1PersistentVolume pv = new V1PersistentVolume();
V1ObjectMeta meta = new V1ObjectMeta();
meta.setName(volumesAddVo.getName());
meta.setNamespace(volumesAddVo.getNameSpace());
pv.setMetadata(meta);
pv.setKind("PersistentVolume");
//设置
V1PersistentVolumeSpec spec = new V1PersistentVolumeSpec();
List<String> accessModes = new LinkedList<>();
accessModes.add(volumesAddVo.getAccessModes());
spec.setAccessModes(accessModes);
//设置挂载
spec.setVolumeMode(volumesAddVo.getVolumeMode());
spec.setStorageClassName(volumesAddVo.getStorageClassName());
V1HostPathVolumeSource pathVolumeSource = new V1HostPathVolumeSource();
pathVolumeSource.setPath(volumesAddVo.getHostPath());
pathVolumeSource.setType(volumesAddVo.getHostPathType());
spec.setHostPath(pathVolumeSource);
//配置容量
Map<String,Quantity> capacityMap = new HashMap<>();
capacityMap.put("storage",new Quantity(volumesAddVo.getCapacity()));
spec.setCapacity(capacityMap);
pv.setSpec(spec);
//回收策略
spec.setPersistentVolumeReclaimPolicy(volumesAddVo.getPersistentVolumeReclaimPolicy());
try {
api.createPersistentVolume(pv,"ture",null,null,null);
} catch (ApiException e) {
log.error("数据卷PV创建失败");
log.error("Status code: {}", e.getCode());
log.error("Reason: {}", e.getResponseBody());
return Boolean.FALSE;
}
return Boolean.TRUE;
}
@Override
public List<ServiceAddVo> services(String nameSpace) {
List<ServiceAddVo> res = new LinkedList<>();
CoreV1Api api = new CoreV1Api();
try {
V1ServiceList listNamespacedService = api.listNamespacedService(nameSpace, "true", false, null, null, null, null, null, null, null, false);
if (listNamespacedService==null){
log.info("服务列表查询失败");
return res;
}
List<V1Service> items = listNamespacedService.getItems();
items.forEach(e->{
ServiceAddVo serviceAddVo = new ServiceAddVo();
V1ObjectMeta metadata = e.getMetadata();
String name = metadata.getName();
serviceAddVo.setName(name);
Map<String, String> labels = metadata.getLabels();
List<LabelsOrKvVo> curLabels = new LinkedList<>();
if (CollectionUtil.isNotEmpty(labels)){
labels.forEach((k,v)->{
LabelsOrKvVo labelsOrKvVo = new LabelsOrKvVo();
labelsOrKvVo.setKey(k);
labelsOrKvVo.setValue(v);
curLabels.add(labelsOrKvVo);
});
}
serviceAddVo.setLabels(curLabels);
OffsetDateTime dateTime = metadata.getCreationTimestamp();
Date date = Date.from(dateTime.toLocalDateTime().toInstant(ZoneOffset.ofHours(8)));
serviceAddVo.setCreateTime(date);
String curNamespace = metadata.getNamespace();
serviceAddVo.setNameSpace(curNamespace);
V1ServiceSpec spec = e.getSpec();
String type = spec.getType();
serviceAddVo.setType(type);
List<V1ServicePort> ports = spec.getPorts();
List<ServicePortVo> curPorts = new LinkedList<>();
if (CollectionUtil.isNotEmpty(ports)){
for (V1ServicePort port : ports) {
ServicePortVo servicePortVo = new ServicePortVo();
Integer nodePort = port.getNodePort();
servicePortVo.setNodePort(nodePort);
IntOrString targetPort = port.getTargetPort();
servicePortVo.setContainerPort(targetPort.getIntValue());
curPorts.add(servicePortVo);
}
}
serviceAddVo.setPorts(curPorts);
res.add(serviceAddVo);
});
} catch (ApiException e) {
e.printStackTrace();
}
return res;
}
@Override
public Boolean applyService(ServiceAddVo serviceAddVo) {
CoreV1Api api = new CoreV1Api();
V1Service v1Service = new V1Service();
List<LabelsOrKvVo> labelVo = serviceAddVo.getLabels();
if (CollectionUtil.isEmpty(labelVo)){
log.info("至少需要输入一个标签");
return Boolean.FALSE;
}
Map<String,String> labels = new HashMap<>(labelVo.size());
for (LabelsOrKvVo labelsOrKvVo : labelVo) {
labels.put(labelsOrKvVo.getKey(), labelsOrKvVo.getValue());
}
v1Service.setApiVersion(serviceAddVo.getVersion());
v1Service.setKind("Service");
V1ObjectMeta meta = new V1ObjectMeta();
meta.setName(serviceAddVo.getName());
meta.setNamespace(serviceAddVo.getNameSpace());
meta.setLabels(labels);
v1Service.setMetadata(meta);
V1ServiceSpec serviceSpec = new V1ServiceSpec();
serviceSpec.setSelector(labels);
serviceSpec.setType(serviceAddVo.getType());
List<ServicePortVo> voPorts = serviceAddVo.getPorts();
if (CollectionUtil.isEmpty(voPorts)){
return Boolean.FALSE;
}
List<V1ServicePort> ports = new LinkedList<>();
for (ServicePortVo portVo : voPorts) {
V1ServicePort v1ServicePort = new V1ServicePort();
v1ServicePort.setPort(portVo.getContainerPort());
v1ServicePort.setProtocol(portVo.getProtocol());
IntOrString intOrString = new IntOrString(portVo.getContainerPort());
v1ServicePort.setTargetPort(intOrString);
v1ServicePort.setNodePort(portVo.getNodePort());
ports.add(v1ServicePort);
}
serviceSpec.setPorts(ports);
v1Service.setSpec(serviceSpec);
try {
api.createNamespacedService(serviceAddVo.getNameSpace(), v1Service, "true", null, null, null);
}catch (ApiException e){
log.error("Status code: {}", e.getCode());
log.error("Reason: {}", e.getResponseBody());
return Boolean.FALSE;
}
return Boolean.TRUE;
}
@Override
public Boolean deleteService(DeleteK8sVo deleteK8sVo) {
CoreV1Api api = new CoreV1Api();
try {
V1DeleteOptions deleteOptions = new V1DeleteOptions();
deleteOptions.setPropagationPolicy(K8sConstants.DELETE_OPTION_FOREGROUND);
api.deleteNamespacedService(deleteK8sVo.getName(),deleteK8sVo.getNameSpace(),null,null,null,false,null,deleteOptions);
} catch (ApiException e) {
log.error("Status code: {}", e.getCode());
log.error("Reason: {}", e.getResponseBody());
return Boolean.FALSE;
}
return Boolean.TRUE;
}
@Override
public Boolean deleteDeployment(DeleteK8sVo deleteK8sVo) {
AppsV1Api api = new AppsV1Api();
try {
V1DeleteOptions deleteOptions = new V1DeleteOptions();
deleteOptions.setPropagationPolicy(K8sConstants.DELETE_OPTION_FOREGROUND);
api.deleteNamespacedDeployment(deleteK8sVo.getName(), deleteK8sVo.getNameSpace(), "true", null, null, false, null, deleteOptions);
} catch (ApiException e) {
log.error("Status code: {}", e.getCode());
log.error("Reason: {}", e.getResponseBody());
return Boolean.FALSE;
}
return Boolean.TRUE;
}
@Override
public Boolean addConfigMap(ConfigMapVo configMapVo) {
CoreV1Api api = new CoreV1Api();
V1ConfigMap configMap = new V1ConfigMap();
Map<String, String> config = new HashMap<>();
List<ConfigVo> configVos = configMapVo.getMaps();
if (CollectionUtil.isNotEmpty(configVos)){
for (ConfigVo configVo : configVos) {
config.put(configVo.getKey(),configVo.getValue());
}
}
configMap.setData(config);
V1ObjectMeta metadata = new V1ObjectMeta();
metadata.setName(configMapVo.getName());
configMap.setMetadata(metadata);
try {
api.createNamespacedConfigMap(configMapVo.getNameSpace(), configMap, "true",null,null,null);
} catch (ApiException e) {
e.printStackTrace();
log.error("Status code: {}", e.getCode());
log.error("Reason: {}", e.getResponseBody());
return Boolean.FALSE;
}
return Boolean.TRUE;
}
}