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

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

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参数上进行了错误配置。你能看出我做错了什么吗?非常感谢。

事件:

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

.Values:

replicaCount: 1
global:
  namespace: default
image:
  repository: node
  tag: 14

# filePath: .
filePath: "/files"
service:
  name: fixit-repair-catalog
  type: ClusterIP
  port: 3000

fullnameOverride: ""

Job:

apiVersion: batch/v1
kind: Job
metadata:
  name: {{ .Release.Name }}-job
  labels:
    app: {{ .Release.Name }}
spec:
  template:
    spec:
      restartPolicy: OnFailure
      containers:
        - name: {{ .Release.Name }}-job
          image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
          command: ["node"]
          args: [ {{ .Files.Get "/files/sendRepairData.js" }} ]
          volumeMounts:
            - name: repair-catalog
              mountPath: /app/files
      volumes:
        - name: repair-catalog
          hostPath:
            path: {{ .Values.filePath }}

sendRepairData.js:

const fs = require('fs');
const http = require('http');

// Function to send repair data
var savedRepairs = [];
function sendRepairData() {
  // Read the catalog JSON file
  try {
    const catalogData = fs.readFileSync('catalog.json');
    const catalog = JSON.parse(catalogData);

    // Access the repairs array from the catalog
    const repairs = catalog.repairs;

    // Process the repairs data as needed
    for (const repair of repairs) {
      const options = {
        host: 'server-clusterip-service',
        port: 3000,
        path: 'api/server/repairs',
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          AuthToken: '',
          apikey: ''
        },
      };

      const req = http.request(options, (res) => {
        let data = '';

        res.on('data', (chunk) => {
          data += chunk;
        });

        res.on('end', () => {
          console.log('Response:', data);
          // save response data for resetting the db in case of error
          savedRepairs.push(JSON.parse(data));

        });
      });

      req.on('error', (error) => {
        console.error('Error:', error.message);
      });

      req.write(JSON.stringify(repair));
      req.end();
    }
  } catch (error) {
    console.error('Error reading catalog file:', error.message);
    throw error;
  }
}


// function to reset the db
function deleteRepairs() {
  savedRepairs.forEach((repair) => {
    const options = {
    host: 'server-clusterip-service',
    port: 3000,
    path: `api/server/repairs/${repair.id}`,
    method: 'Delete',
    headers: {
      'Content-Type': 'application/json',
      AuthToken: '', // Replace with the actual AuthToken used by your server
      apikey: ''
    },
  };

  const req = http.request(options, (res) => {
    let data = '';

    res.on('data', (chunk) => {
      data += chunk;
    });

    res.on('end', () => {
      console.log('Response:', data);
    });
  });

  req.on('error', (error) => {
    console.error('Error:', error.message);
  });
  req.end();
  });
  
}

function uploadRepairCatalog() {
  try {
    sendRepairData();
  } catch (error){
    deleteRepairs();
    throw error;
  }
}
// uploadRepairCatalog();

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:

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

.Values:

replicaCount: 1
global:
  namespace: default
image:
  repository: node
  tag: 14

# filePath: .
filePath: "/files"
service:
  name: fixit-repair-catalog
  type: ClusterIP
  port: 3000


fullnameOverride: ""

Job:

apiVersion: batch/v1
kind: Job
metadata:
  name: {{ .Release.Name }}-job
  labels:
    app: {{ .Release.Name }}
spec:
  template:
    spec:
      restartPolicy: OnFailure
      containers:
        - name: {{ .Release.Name }}-job
          image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
          command: ["node"]
          args: [ {{ .Files.Get "/files/sendRepairData.js" }} ]
          volumeMounts:
            - name: repair-catalog
              mountPath: /app/files
      volumes:
        - name: repair-catalog
          hostPath:
            path: {{ .Values.filePath }}

sendRepairData.js:

const fs = require('fs');
const http = require('http');

// Function to send repair data
var savedRepairs = [];
function sendRepairData() {
  // Read the catalog JSON file
  try {
    const catalogData = fs.readFileSync('catalog.json'); 
    const catalog = JSON.parse(catalogData);

    // Access the repairs array from the catalog
    const repairs = catalog.repairs;

    // Process the repairs data as needed
    for (const repair of repairs) {
      const options = {
        host: 'server-clusterip-service', 
        port: 3000,
        path: 'api/server/repairs',
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          AuthToken: '', 
          apikey: ''
        },
      };

      const req = http.request(options, (res) => {
        let data = '';

        res.on('data', (chunk) => {
          data += chunk;
        });

        res.on('end', () => {
          console.log('Response:', data);
          // save response data for resetting the db in case of error
          savedRepairs.push(JSON.parse(data));

        });
      });

      req.on('error', (error) => {
        console.error('Error:', error.message);
      });

      req.write(JSON.stringify(repair));
      req.end();
    }
  } catch (error) {
    console.error('Error reading catalog file:', error.message);
    throw error;
  }
}


// function to reset the db
function deleteRepairs() {
  savedRepairs.forEach((repair) => {
    const options = {
    host: 'server-clusterip-service', 
    port: 3000, 
    path: `api/server/repairs/${repair.id}`,
    method: 'Delete',
    headers: {
      'Content-Type': 'application/json',
      AuthToken: '',  by your server
      apikey: ''
    },
  };

  const req = http.request(options, (res) => {
    let data = '';

    res.on('data', (chunk) => {
      data += chunk;
    });

    res.on('end', () => {
      console.log('Response:', data);
    });
  });

  req.on('error', (error) => {
    console.error('Error:', error.message);
  });
  req.end();
  });
  
}

function uploadRepairCatalog() {
  try {
    sendRepairData();
  } catch (error){
    deleteRepairs();
    throw error;
  }
}
// uploadRepairCatalog();

console.log('cron job done');

答案1

得分: 1

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

特别是,这个YAML块

      volumes:
        - name: repair-catalog
          hostPath:
            path: {{ .Values.filePath }}

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

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

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

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

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

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

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

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

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

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

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

      volumes:
        - name: repair-catalog
          hostPath:
            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

FROM node:14
WORKDIR /app
COPY sendRepairData.js ./
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

docker build -t registry.example.com/send-repair-data:20230526 .
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

image:
  repository: registry.example.com/send-repair-data
  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.

spec:
  template:
    spec:
      restartPolicy: OnFailure
      containers:
        - name: send-repair-data  # this name does not need to be configurable
          image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
      # 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:

确定