前置条件
-
已安装
Dinky(版本1.2.3) -
准备
Flink镜像地址(版本1.17.2) -
已安装
K8S(版本1.20.0) -
已安装
Docker(版本19.03.12) -
已安装
Harbor(版本2.0) -
已安装
Minio(Flink SQL任务不需要,Flink Jar任务需要)
本文只做 Kubernetes Application 模式任务的提交,其他模式不在本文的探讨范围内。
K8S初始环境
创建K8S命名空间
csharp
# 创建一个名为 flink 的命名空间
kubectl create namespace flink
创建服务账号和角色绑定
ini
# 在名字为 flink 的命名空间中,创建一个名为 flink-service-account 的 serviceaccount
kubectl create serviceaccount flink-service-account -n flink
# 创建 RoleBinding,绑定 ClusterRole admin 到该 ServiceAccount
kubectl create rolebinding dinky-admin --clusterrole=admin --serviceaccount=flink:flink-service-account -n flink
-
rolebinding dinky-admin:创建一个名为dinky-admin的RoleBinding; -
---clusterrole=admin:指定要绑定的角色是集群角色admin。虽然admin是一个ClusterRole(定义在集群级别),但通过RoleBinding可以将其限制在某个命名空间内生效; -
---serviceaccount=flink:flink-service-account:指定目标ServiceAccount,格式为:
<namespace>:<serviceaccount-name>; -
-n flink:表示创建的这个RoleBinding作用于flink命名空间;
创建Secret敏感信息
该 Secret 用于存储访问私有 Docker 镜像仓库 Harbor 所需的认证信息。
-
harbor-login-registry是创建的Secret的名称; -
--docker-username=admin表示Harbor登录账号; -
--docker-password表示Harbor登录密码; -
-n flink表示这个Secret在flink这个命名空间下创建;
css
kubectl create secret docker-registry harbor-login-registry --docker-server=harbor-domain --docker-username=admin --docker-password=****** -n flink
制作Docker镜像
理论上可以直接用官方的Flink镜像,但是我们最好还是在官方镜像的基础上构建一个新的基于我们自身需求的镜像。 构建镜像所需依赖清单如下:
sql
config
....flink-conf.yaml
usrlib
....flink-s3-fs-hadoop-1.17.2.jar
....dinky-app-1.17-1.2.3-jar-with-dependencies.jar
lib
....mysql-connector-java-8.0.19.jar
....flink-connector-jdbc-3.1.1-1.17.jar
....flink-sql-connector-mysql-cdc-2.4.1.jar
Dockerfile
-
config目录保存flink配置文件; -
usrlib目录保存用户所需的jar包; -
lib目录保存flink所需的jar包,可依自己情况放入合适的依赖,不做强制要求; -
Dockerfile文件放在根目录下;
完整的 Dockerfile 代码如下:
bash
# 使用官方 Flink 镜像作为基础镜像
FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/flink:1.17.2-scala_2.12-java8
# 设置时区(可选)
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 设置工作目录
WORKDIR /opt/flink
# 在容器内创建以下目录
RUN mkdir -p /opt/flink/usrlib
RUN mkdir -p /opt/flink/plugins/s3-fs-hadoop
# 添加自定义配置文件(可选)
# dinky 提交作业时并未生效,将会被 dinky 集群中的 flink 配置替换
# 将宿主文件 config/flink-conf.yaml 覆盖到镜像的 ${WORKDIR}/conf/ 目录下
COPY config/flink-conf.yaml ./conf/
# 兼容dinky替换jar包
# 删除镜像内 ${WORKDIR}/lib/ 下的所有 loader 包
RUN rm -rf ./lib/flink-table-planner-loader-*.jar
# 将镜像内 ${WORKDIR}/opt/ 下的 table planner 包移动到 ${WORKDIR}/lib/ 下
RUN mv ./opt/flink-table-planner_2.12-*.jar ./lib/
# 添加自定义jar包(可选)
# 将宿主机上 lib 目录下的所有 Flink 依赖包复制到镜像的 ${WORKDIR}/lib 下
COPY lib/*.jar ./lib/
# 将宿主机上 usrlib 目录下的 dinky app 包复制到镜像的 ${WORKDIR}/usrlib 下,这个包在后文中 dinky 的集群配置中会使用到,它是容器启动的包
COPY usrlib/dinky-app-1.17-1.2.3-jar-with-dependencies.jar ./usrlib/
# 将镜像内 ${WORKDIR}/opt/ 下的 flink-s3 依赖包复制到镜像内 flink 的插件目录下
RUN cp ./opt/flink-s3-fs-hadoop-1.17.2.jar ./plugins/s3-fs-hadoop/
# 设置环境变量
ENV FLINK_HOME=/opt/flink
ENV PATH=$FLINK_HOME/bin:$PATH
# 暴露必要的端口
# 8081 - Web UI
# 6123 - TaskManager RPC
EXPOSE 8081 6123
# 设置容器启动命令(根据需要修改)
CMD ["bash"]

构建Docker镜像
perl
# 构建名为 my-flink-dinky 的镜像,版本号 1.0
docker build -t my-flink-dinky:1.0 .
# 给 my-flink-dinky 镜像打标签
docker tag my-flink-dinky:1.0 harbor-domain/project-name/my-flink-dinky:1.0
# 将镜像推送到远程 Harbor 仓库
docker push harbor-domain/project-name/my-flink-dinky:1.0
如果docker拉取镜像失败,有可能是因为网络限制,编辑或创建 /etc/docker/daemon.json,将镜像修改成你的阿里云账号镜像地址。
json
{
"registry-mirrors": ["https://<your-id>.mirror.aliyuncs.com"]
"insecure-registries" : [
"registry.docker-cn.com",
"docker.mirrors.ustc.edu.cn"
],
"debug": true,
"experimental": false
}
拉取成功后,查看构建好的镜像
python
docker images --filter "reference=*flink*"
配置 K8S 集群信息
打开 Dinky 界面,按照如下图所示步骤新建一个 K8S 集群配置

在新建窗口填写集群配置信息:
-
类型:
Kubernetes Application -
集群配置名称(自定义):
Flink_K8S -
是否启用:勾选启用
-
暴露端口类型:
NodePort -
Kubernetes命名空间:flink -
K8S KubeConfig:从本地文件加载会自动带入

-
k8s提交账号:flink-service-account -
Flink镜像地址:harbor-domain/project-name/my-flink-dinky:1.0 -
Flink配置文件路径:/opt/flink/conf/
-
JM Pod Template和TM Pod Template:
yaml
apiVersion: v1
kind: Pod
spec:
containers:
- name: flink-main-container
imagePullPolicy: Always
imagePullSecrets:
- name: harbor-login-registry

-
Jar 文件路径:
local:///opt/flink/usrlib/dinky-app-1.17-1.2.3-jar-with-dependencies.jar -
其他预设配置可以根据自身实际使用需要,设置内存大小、插槽数等;

参数解读



Dinky 资源配置
提交 Flink Jar 任务时,因为 Jar 包路径在 Dinky 中配置,只支持 file:// 协议和 rs:/ 协议,rs 协议默认是保存本地服务器路径,所以这两种协议实际上都是保存在 Dinky 本地,但是任务提交到 K8S 容器之后是没办法读取 Dinky 服务的文件的,所以需要在 Dinky 中将资源配置修改为 S3 协议或者 hdfs 协议,再通过与 rs 协议桥接的方式,实现在 K8S 容器内读取远程 Jar 文件的功能。本文使用的是 Minio 的 S3 协议。 具体配置方式如下图,重点是首先要先关闭是否启用Resource开关,再进行配置修改,最后打开开关让配置生效:

-
存储模式选择
OSS; -
将
Minio的Endpoint Url(默认9000端口)、Access Key和Secret Key写入到配置表单中; -
上传目录根路径(
/dinky)和存储桶名称(dinky)使用默认就好;
Minio 创建桶
创建一个桶名为 dinky,并将访问权限设置为 public

在 Dinky 资源管理中上传的文件最终会保存到 Minio 里,根目录是 /dinky/dinky,我这里上传了一个 Flink 官方流任务 TopSpeedWindowing.jar


配置解读

提交 Application 任务
-
在数据开发中创建一个
Flink Jar类型的任务; -
工具栏上有个下拉框选择我们创建好的集群
Flink_K8S; -
程序路径可以在资源配置中选择,可以自己手写
rs:/job/TopSpeedWindowing.jar,rs协议会桥接到s3协议,从而访问Minio; -
程序运行类:
org.apache.flink.streaming.examples.windowing.TopSpeedWindowing -
点击绿色三角形的启动按钮

在 K8S 的 Flink 命名空间访问容器组页面,可以看到两个容器已经启动,一个是 Flink Jobmanager,另一个是 Flink TaskManager。

如果是提交 Flink SQL 任务则更简单,不需要配置 S3,也不需要 Minio,只需要在 Dinky 中提交任务即可,Dinky 会将 Flink SQL 代码写入到 K8S 的 CnfigMap 配置供容器使用。
常用命令
Docker
Shell
# 构建Dockerfile
docker build -t image-name:tag .
# 镜像打标签
docker tag image-name:tag harbor-domain/project-name/image-name:tag
# 推送镜像
docker push harbor-domain/project-name/image-name:tag
# 查看docker镜像中某个目录的文件列表:
docker run --rm harbor-domain/project-name/image-name:tag ls -l /opt/flink/usrlib
# 过滤条件查看docker镜像:
docker images --filter "reference=*flink*"
# 从docker容器拷贝出来文件到宿主机:
docker cp 容器名或容器ID:容器内文件路径 宿主机目标路径
# 示例:
docker cp dinky:/opt/dinky/jar/dinky-app-1.17-1.2.3-jar-with-dependencies.jar /opt/dinky/
# 查看容器日志
docker logs -f --tail=200 <container name or id>
K8S
Shell
# 查看容器信息
kubectl get pods pods,svc,sa -n <namespace>
kubectl get clusterrolebinding <rolebinding-name> -o yaml
# 查看日志:
kubectl get pod -n <namespace> -l component=jobmanager
kubectl describe pod <pod name> -n flink
kubectl -n flink logs <pod name> -c flink-main-container --previous
# k8s查看secret:
kubectl get secret -n <namespace> --field-selector type=kubernetes.io/dockerconfigjson
# k8s查看pod文件列表:
kubectl exec <pod name> -- ls /opt/flink
# k8s进入pod的交互式shell:
kubectl -n <namespace> exec -it <pod name> -- /bin/sh
# 查看资源:
kubectl get pods -n <namespace> | grep <deployment-name>
# 示例:
kubectl get pods -n flink | grep my-first-application-cluster
# 删除k8s pod的所有容器资源:
kubectl delete all -l app=<flink-cluster-id> -n <namespace>
# 示例:
kubectl delete all -l app=my-first-application-cluster -n flink
# 删除k8s命名空间:
kubectl delete ns <namespace>
# 示例:
kubectl delete ns flink
Flink
Shell
# Flink 命令方式提交 Jar 任务到 K8S Application
bin/flink run-application \
--target kubernetes-application \
-Dkubernetes.cluster-id=my-first-application-cluster \
-Dkubernetes.container.image=harbor-domain/project-name/my-flink-dinky:latest \
-Dkubernetes.jobmanager.replicas=1 \
-Dkubernetes.namespace=flink \
-Dkubernetes.jobmanager.service-account=flink-service-account \
-Dexternal-resource.limits.kubernetes.cpu=2000m \
-Dexternal-resource.limits.kubernetes.memory=2Gi \
-Dexternal-resource.requests.kubernetes.cpu=1000m \
-Dexternal-resource.requests.kubernetes.memory=1Gi \
-Dkubernetes.rest-service.exposed.type=NodePort \
local:///opt/flink/examples/streaming/TopSpeedWindowing.jar
参考
www.dinky.org.cn/docs/next/u... jishuzhan.net/article/193... www.cnblogs.com/liugp/p/167... juejin.cn/post/738703...