英文:
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.js
和catalog.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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论