JavaScript函数在使用Kubernetes Job创建Pod时未运行

huangapple go评论116阅读模式
英文:

Javascript function not running on pod creation using a Kubernetes Job

问题

I have translated the content you provided. Here is the translated text:

我有一个AKS集群,其中包含一个Node.js服务器和一个MongoDB。我想使用服务器端点从JSON文件中的维修目录创建MongoDB记录。

为此,我创建了一个Helm图表,其中包含sendRepairData.jscatalog.json文件,它们位于files文件夹下,以及一个Job,该Job应该创建一个Node pod并运行sendRepairData.js文件。

当我安装图表时,该Job确实创建了pod并将状态设置为已完成,但没有数据发送到服务器,并且当我在该pod上运行kubectl logs命令时,我没有获得任何日志。

因此,为了调试它,我注释掉了函数并只是打印到控制台,但仍然没有从pod中获取到日志。我对Kubernetes相当陌生,我猜我可能在Job的volumeMounts和volumes参数上进行了错误配置。你能看出我做错了什么吗?非常感谢。

事件:

  1. 8秒前 正常 已调度 pod/fixit-repair-catalog-job-pzcb5 已成功分配给aks-default-80269438-vmss000000
  2. 8秒前 正常 已拉取 pod/fixit-repair-catalog-job-pzcb5 容器镜像“node:14”已经存在于机器上
  3. 8秒前 正常 已创建 pod/fixit-repair-catalog-job-pzcb5 已创建容器fixit-repair-catalog-job
  4. 8秒前 正常 已启动 pod/fixit-repair-catalog-job-pzcb5 已启动容器fixit-repair-catalog-job
  5. 8秒前 正常 成功创建 job/fixit-repair-catalog-job 创建了podfixit-repair-catalog-job-pzcb5
  6. 4秒前 正常 已完成 job/fixit-repair-catalog-job 任务已完成

.Values:

  1. replicaCount: 1
  2. global:
  3. namespace: default
  4. image:
  5. repository: node
  6. tag: 14
  7. # filePath: .
  8. filePath: "/files"
  9. service:
  10. name: fixit-repair-catalog
  11. type: ClusterIP
  12. port: 3000
  13. fullnameOverride: ""

Job:

  1. apiVersion: batch/v1
  2. kind: Job
  3. metadata:
  4. name: {{ .Release.Name }}-job
  5. labels:
  6. app: {{ .Release.Name }}
  7. spec:
  8. template:
  9. spec:
  10. restartPolicy: OnFailure
  11. containers:
  12. - name: {{ .Release.Name }}-job
  13. image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
  14. command: ["node"]
  15. args: [ {{ .Files.Get "/files/sendRepairData.js" }} ]
  16. volumeMounts:
  17. - name: repair-catalog
  18. mountPath: /app/files
  19. volumes:
  20. - name: repair-catalog
  21. hostPath:
  22. path: {{ .Values.filePath }}

sendRepairData.js:

  1. const fs = require('fs');
  2. const http = require('http');
  3. // Function to send repair data
  4. var savedRepairs = [];
  5. function sendRepairData() {
  6. // Read the catalog JSON file
  7. try {
  8. const catalogData = fs.readFileSync('catalog.json');
  9. const catalog = JSON.parse(catalogData);
  10. // Access the repairs array from the catalog
  11. const repairs = catalog.repairs;
  12. // Process the repairs data as needed
  13. for (const repair of repairs) {
  14. const options = {
  15. host: 'server-clusterip-service',
  16. port: 3000,
  17. path: 'api/server/repairs',
  18. method: 'POST',
  19. headers: {
  20. 'Content-Type': 'application/json',
  21. AuthToken: '',
  22. apikey: ''
  23. },
  24. };
  25. const req = http.request(options, (res) => {
  26. let data = '';
  27. res.on('data', (chunk) => {
  28. data += chunk;
  29. });
  30. res.on('end', () => {
  31. console.log('Response:', data);
  32. // save response data for resetting the db in case of error
  33. savedRepairs.push(JSON.parse(data));
  34. });
  35. });
  36. req.on('error', (error) => {
  37. console.error('Error:', error.message);
  38. });
  39. req.write(JSON.stringify(repair));
  40. req.end();
  41. }
  42. } catch (error) {
  43. console.error('Error reading catalog file:', error.message);
  44. throw error;
  45. }
  46. }
  47. // function to reset the db
  48. function deleteRepairs() {
  49. savedRepairs.forEach((repair) => {
  50. const options = {
  51. host: 'server-clusterip-service',
  52. port: 3000,
  53. path: `api/server/repairs/${repair.id}`,
  54. method: 'Delete',
  55. headers: {
  56. 'Content-Type': 'application/json',
  57. AuthToken: '', // Replace with the actual AuthToken used by your server
  58. apikey: ''
  59. },
  60. };
  61. const req = http.request(options, (res) => {
  62. let data = '';
  63. res.on('data', (chunk) => {
  64. data += chunk;
  65. });
  66. res.on('end', () => {
  67. console.log('Response:', data);
  68. });
  69. });
  70. req.on('error', (error) => {
  71. console.error('Error:', error.message);
  72. });
  73. req.end();
  74. });
  75. }
  76. function uploadRepairCatalog() {
  77. try {
  78. sendRepairData();
  79. } catch (error){
  80. deleteRepairs();
  81. throw error;
  82. }
  83. }
  84. // uploadRepairCatalog();
  85. console.log('cron job done');
英文:

I have an AKS cluster with a Node.js server and a mongo db. I want to create MongoDb records from a repair catalog in a json file using the server endpoint.

To do so I created an Helm chart , with the sendRepiarData.js and the catalog.json files under a files folder and a Job which should create a Node pod and run the sendRepiarData.js file.

When I install the chart the Job does create the pod and set the status to completed but no data is sent to the server and I don't get any logs from the pod when I run the kubectl logs command on that pod.

So to debug it I commented out the function and just printed to console, but still no logs from the pod. I'm fairly new to Kubernetes and I guess I'm misconfiguring the Job's volumeMounts a volumes parameters.
Can you spot what I'm doing wrong?
Many thanks.

Events:

  1. 8s Normal Scheduled pod/fixit-repair-catalog-job-pzcb5 Successfully assigned default/fixit-repair-catalog-job-pzcb5 to aks-default-80269438-vmss000000
  2. 8s Normal Pulled pod/fixit-repair-catalog-job-pzcb5 Container image "node:14" already present on machine
  3. 8s Normal Created pod/fixit-repair-catalog-job-pzcb5 Created container fixit-repair-catalog-job
  4. 8s Normal Started pod/fixit-repair-catalog-job-pzcb5 Started container fixit-repair-catalog-job
  5. 8s Normal SuccessfulCreate job/fixit-repair-catalog-job Created pod: fixit-repair-catalog-job-pzcb5
  6. 4s Normal Completed job/fixit-repair-catalog-job Job completed

.Values:

  1. replicaCount: 1
  2. global:
  3. namespace: default
  4. image:
  5. repository: node
  6. tag: 14
  7. # filePath: .
  8. filePath: "/files"
  9. service:
  10. name: fixit-repair-catalog
  11. type: ClusterIP
  12. port: 3000
  13. fullnameOverride: ""

Job:

  1. apiVersion: batch/v1
  2. kind: Job
  3. metadata:
  4. name: {{ .Release.Name }}-job
  5. labels:
  6. app: {{ .Release.Name }}
  7. spec:
  8. template:
  9. spec:
  10. restartPolicy: OnFailure
  11. containers:
  12. - name: {{ .Release.Name }}-job
  13. image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
  14. command: ["node"]
  15. args: [ {{ .Files.Get "/files/sendRepairData.js" }} ]
  16. volumeMounts:
  17. - name: repair-catalog
  18. mountPath: /app/files
  19. volumes:
  20. - name: repair-catalog
  21. hostPath:
  22. path: {{ .Values.filePath }}

sendRepairData.js:

  1. const fs = require('fs');
  2. const http = require('http');
  3. // Function to send repair data
  4. var savedRepairs = [];
  5. function sendRepairData() {
  6. // Read the catalog JSON file
  7. try {
  8. const catalogData = fs.readFileSync('catalog.json');
  9. const catalog = JSON.parse(catalogData);
  10. // Access the repairs array from the catalog
  11. const repairs = catalog.repairs;
  12. // Process the repairs data as needed
  13. for (const repair of repairs) {
  14. const options = {
  15. host: 'server-clusterip-service',
  16. port: 3000,
  17. path: 'api/server/repairs',
  18. method: 'POST',
  19. headers: {
  20. 'Content-Type': 'application/json',
  21. AuthToken: '',
  22. apikey: ''
  23. },
  24. };
  25. const req = http.request(options, (res) => {
  26. let data = '';
  27. res.on('data', (chunk) => {
  28. data += chunk;
  29. });
  30. res.on('end', () => {
  31. console.log('Response:', data);
  32. // save response data for resetting the db in case of error
  33. savedRepairs.push(JSON.parse(data));
  34. });
  35. });
  36. req.on('error', (error) => {
  37. console.error('Error:', error.message);
  38. });
  39. req.write(JSON.stringify(repair));
  40. req.end();
  41. }
  42. } catch (error) {
  43. console.error('Error reading catalog file:', error.message);
  44. throw error;
  45. }
  46. }
  47. // function to reset the db
  48. function deleteRepairs() {
  49. savedRepairs.forEach((repair) => {
  50. const options = {
  51. host: 'server-clusterip-service',
  52. port: 3000,
  53. path: `api/server/repairs/${repair.id}`,
  54. method: 'Delete',
  55. headers: {
  56. 'Content-Type': 'application/json',
  57. AuthToken: '', by your server
  58. apikey: ''
  59. },
  60. };
  61. const req = http.request(options, (res) => {
  62. let data = '';
  63. res.on('data', (chunk) => {
  64. data += chunk;
  65. });
  66. res.on('end', () => {
  67. console.log('Response:', data);
  68. });
  69. });
  70. req.on('error', (error) => {
  71. console.error('Error:', error.message);
  72. });
  73. req.end();
  74. });
  75. }
  76. function uploadRepairCatalog() {
  77. try {
  78. sendRepairData();
  79. } catch (error){
  80. deleteRepairs();
  81. throw error;
  82. }
  83. }
  84. // uploadRepairCatalog();
  85. console.log('cron job done');

答案1

得分: 1

在Kubernetes中,你不能真正运行一个未经修改的基础镜像并通过挂载方式注入你的应用程序。我将其视为避免在本地一行安装Node的偶发Docker "模式",但在Kubernetes中,你无法可靠地访问主机系统。要有效使用Kubernetes,你几乎必须创建一个自定义镜像并将其推送到某个注册表。

特别是,这个YAML块

  1. volumes:
  2. - name: repair-catalog
  3. hostPath:
  4. path: {{ .Values.filePath }}

挂载了一个来自Pod所在的任何Node的任意目录。它无法从你的本地计算机复制内容;事实上,Kubernetes不会追踪Job可能提交的位置,也不能连接到集群外。在大多数情况下,你应该避免使用 hostPath: 挂载。

相反,你需要创建一个自定义镜像。如果你只是想运行这个脚本而且它没有任何依赖关系,Dockerfile非常简单:

  1. FROM node:14
  2. WORKDIR /app
  3. COPY sendRepairData.js ./
  4. CMD ["node", "./sendRepairData.js"]

然后,你需要发布该镜像或以某种方式将镜像放入集群中。通用答案,假设存在某个外部镜像仓库,如下所示:

  1. docker build -t registry.example.com/send-repair-data:20230526 .
  2. docker push registry.example.com/send-repair-data:20230526

在本地环境中,你可能可以在不使用 "push" 命令的情况下完成。例如,Minikube有一种方法可以在构建之前直接使用嵌入式Docker守护程序,只要在构建之前运行 eval $(minikube docker-env);Kind有一个记录在 运行本地注册表的路径。

你需要修改你的 values.yaml 来指向刚刚构建的镜像

  1. image:
  2. repository: registry.example.com/send-repair-data
  3. tag: "20230526"

然后在Job YAML中,你不需要提供文件内容或完全覆盖命令,所有这些细节都已经嵌入到镜像中。

  1. spec:
  2. template:
  3. spec:
  4. restartPolicy: OnFailure
  5. containers:
  6. - name: send-repair-data # 这个名称不需要可配置
  7. image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
  8. # 结束
英文:

In Kubernetes, you can't really run an unmodified base image and inject your application through mounts. I see this as an occasional Docker "pattern" to avoid the one-line installation of Node locally, but in Kubernetes you can't reliably access the host system. To use Kubernetes effectively, you all but must create a custom image and push it to some registry.

In particular, this block of YAML

  1. volumes:
  2. - name: repair-catalog
  3. hostPath:
  4. path: {{ .Values.filePath }}

mounts an arbitrary directory from whichever Node the Pod is running on. It cannot copy content from your local machine; indeed, Kubernetes doesn't track from where a Job might have been submitted, and can't connect back out of the cluster. In most uses you should avoid hostPath: mounts.

Instead you need to create a custom image. If you're just trying to run this script and it doesn't have any dependencies, the Dockerfile is pretty straightfoward

  1. FROM node:14
  2. WORKDIR /app
  3. COPY sendRepairData.js ./
  4. CMD ["node", "./sendRepairData.js"]

You then need to either publish the image or get the image into the cluster somehow. The generic answer, assuming some external image repository exists, looks like

  1. docker build -t registry.example.com/send-repair-data:20230526 .
  2. docker push registry.example.com/send-repair-data:20230526

In local environments you may be able to get away without the "push" command. Minikube for example has a way to directly use an embedded Docker daemon so long as you eval $(minikube docker-env) before building; Kind has a documented path to run a local registry.

You need to change your values.yaml to point at the image you just built

  1. image:
  2. repository: registry.example.com/send-repair-data
  3. tag: "20230526"

Then in the Job YAML, you don't need to provide the file content or override the command at all, all of these details are already embedded in the image.

  1. spec:
  2. template:
  3. spec:
  4. restartPolicy: OnFailure
  5. containers:
  6. - name: send-repair-data # this name does not need to be configurable
  7. image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
  8. # the end

huangapple
  • 本文由 发表于 2023年5月26日 17:11:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/76339332.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定