如何在 kubernetes 上使用 redis 部署 node.js?

How to deploy a node.js with redis on kubernetes?

我有一个非常简单的node.js应用程序(HTTP服务),其中"talks"到redis。我想创建一个部署并 运行 使用 minikube。

根据我的理解,我的应用程序需要一个基于 docker 图像的 kubernetes Pod。这是我的 Dockerfile:

FROM node:8.9.1
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 8080
CMD ["npm", "start"]

我用 docker build -t my-app .

构建 docker 图像

接下来,我为我的应用的 Pod 创建了一个 Pod 定义:

apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
  - name: my-app
    image: my-app:latest
    imagePullPolicy: Never
    ports:
    - containerPort: 8080

到目前为止,还不错。但是从现在开始,我不知道如何进行redis:

  1. redis 应该是另一个 Pod,还是一个服务(就 Kubernetes 种类而言)?

  2. 如何从我的应用程序内部引用 redis?根据redis是否会被定义为Pod/Service,如何获取连接URL和端口?我阅读了有关 Kubernetes 创建的环境变量的信息,但我不确定这些是否适用于 Pods 或服务。

  3. 如何在单一配置下聚合两者(我的应用程序和 redis)?如何确保首先启动 redis,然后启动我的应用程序(这需要 运行ning redis 实例),以及如何将我的 HTTP 端点公开给 "outside world"?我阅读了有关部署的信息,但我不确定如何将这些部分连接在一起。

理想情况下,我希望所有配置都包含在 YAML 文件中,这样在一天结束时,整个基础设施都可以通过一个命令启动。

  1. 是的,你需要一个单独的 deployementservice for redis

  2. 使用kubernetes服务发现,应该内置,KubeDNS,CoreDNS

  3. 使用就绪和活跃度探测

是的,您可以编写一个大的 yaml 文件来描述所有部署和服务。然后:

kubectl apply -f yourfile.yml

或者您可以将 yaml 放在单独的文件中,然后执行 :

 kubectl apply -f dir/

我建议你进一步阅读 k8s 文档,但一般来说你上面提出的问题:

  1. 是的,另一个 pod(具有相关配置)和附加服务取决于您的用例,检查这个很好的例子:https://kubernetes.io/docs/tutorials/configuration/configure-redis-using-configmap/
  2. 使用服务,在此处阅读更多内容:https://kubernetes.io/docs/concepts/services-networking/connect-applications-service/
  3. 有几种管理依赖项的方法 - 搜索部署依赖项,但通常您可以将它们附加到具有就绪端点的同一文件中,并使用服务公开 - 在项目符号 2 的 link 中阅读更多信息

我会 运行 在单独的 pod 中使用 redis(即:这样您的网络应用程序不会在自身崩溃时关闭 redis 服务器)。

这是您的 redis 部署和服务:

deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
spec:
  selector:
    matchLabels:
      app: redis
  replicas: 1
  template:
    metadata:
      labels:
        app: redis
    spec:
      volumes:
        - name: host-sys
          hostPath:
            path: /sys
      initContainers:
        - name: disable-thp
          image: redis:4.0-alpine
          volumeMounts:
            - name: host-sys
              mountPath: /host-sys
          command: ["sh", "-c", "echo never > /host-sys/kernel/mm/transparent_hugepage/enabled"]
      containers:
      - name: redis
        image: redis:4.0-alpine
        imagePullPolicy: IfNotPresent
        resources:
          requests:
            cpu: 350m
            memory: 1024Mi
        ports:
        - containerPort: 6379

service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: redis
  labels:
    app: redis
spec:
  ports:
  - port: 6379
    name: redis
  selector:
    app: redis

由于我们公开了一个 kubernetes Service,您可以通过主机名访问您的 redis 实例,或者是 "service name",即 redis

您可以在 https://github.com/mateothegreat/k8-byexamples-redis 查看我的 kubernetes redis 存储库。如果你想要更简单的路线,你可以简单地 运行 make install

祝你好运,如果您仍然遇到困难,请联系我们!

我想我找到了解决方案(使用部署和服务)。

对于我的部署,我在一个 Pod 中使用了两个容器(webapp + redis),因为 webapp 在没有活动的 redis 实例的情况下 运行 没有意义,另外它连接到 redis应用程序启动。我在这个推理上可能是错误的,所以如果你有不同的看法,请随时纠正我。

这是我的部署:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-deployment
spec:
  selector:
    matchLabels:
      app: my-app-deployment
  template:
    metadata:
      labels:
        app: my-app-deployment
    spec:
      containers:
      - name: redis
        image: redis:latest
        ports:
        - containerPort: 6379
        volumeMounts:
        - mountPath: /srv/www
          name: redis-storage
      - name: my-app
        image: my-app:latest
        imagePullPolicy: Never
        ports:
        - containerPort: 8080
      volumes:
      - name: redis-storage
        emptyDir: {}

这里是服务定义:

apiVersion: v1
kind: Service
metadata:
  name: my-app-service
spec:
  ports:
  - port: 8080
    protocol: TCP
  type: NodePort
  selector:
    app: my-app-deployment

我使用以下方法创建部署: kubectl create -f deployment.yaml 然后,我使用 kubectl create -f service.yaml 创建服务 我用 minikube ip 读取 IP 并从 kubectl describe service my-app-service.

的输出中提取端口

我同意前面所有的回答。我只是想通过执行单个命令来使事情变得更简单。

首先,在文件中为 redis 创建必要的清单 redis.yaml 并服务以将其暴露在外部。

apiVersion: v1
kind: Service
metadata:
  name: redis
  labels:
    app: node-redis
spec:
  ports:
  - name: redis
    port: 6379
    targetPort: 6379
  type: NodePort
  selector:
    app: node-redis
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
spec:
  selector:
    matchLabels:
      app: node-redis
  replicas: 1
  template:
    metadata:
      labels:
        app: node-redis
    spec:
      containers:
      - name: redis
        image: redis:latest
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 6379
        # data volume where redis writes data
        volumeMounts:
        - name: data
          mountPath: /data
          readOnly: false
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: redis-data
---
# data volume
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: redis-data
  labels:
    app: node-redis
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 100Mi

接下来将您应用程序的清单放在另一个文件中,比如 my-app.yaml。这里我放了volume字段,这样你就可以使用redis存储的数据了。

apiVersion: v1
kind: Pod
metadata:
  name: my-app
  labels:
    app: node-redis
spec:
  containers:
  - name: my-app
    image: my-app:latest
    ports:
    - containerPort: 8080
    # data volume from where my-app read data those are written by redis
    volumeMounts:
    - name: data
      mountPath: /data
      readOnly: false
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: redis-data

现在我们可以使用下面的 bash 文件 my-app.sh.

#!/bin/bash

kubectl create -f redis.yaml

pod_name=$(kubectl get po -l app=node-redis | grep app-with-redis | awk '{print }')

# check whether redis server is ready or not
while true; do
  pong=$(kubectl exec -it $pod_name -c redis redis-cli ping)
  if [[ "$pong" == *"PONG"* ]]; then
    echo ok;
    break
  fi
done

kubectl create -f my-app.yaml

只需 运行 chmod +x my-app.sh; ./my-app.sh 即可部署。得到url运行minikube service redis --url。您可以类似地为您的应用获取 url。唯一的问题是您的应用程序需要 nodePort 类型的服务才能从集群外部访问它。

所以,现在一切都在你手中。