在一个Kubernetes Pod中运行Nginx和Go容器的详细指南

120 阅读3分钟

我们有一个应用程序,其中使用了Nginx和Go容器。Nginx容器将请求代理给Go容器。Nginx暴露了端口8080 ,我们把它映射到端口80 ,所以它可以通过端口80 。然后,Nginx通过端口9090 ,这是一个静态端口,与Go容器对话。我们将使用Kubernetes卷来配置Nginx,而不是创建一个自定义镜像。

结构

├── Makefile
├── deploy
│   └── k8s
│       ├── configmap.yaml
│       ├── deployment.yaml
│       └── service.yaml
├── docker
│   └── dev
│       ├── docker-compose.yaml
│       ├── go
│       │   └── Dockerfile
│       └── nginx
│           ├── Dockerfile
│           └── default.conf
└── main.go

文件

deployment.yaml

apiVersion: apps/v1
kind: Deployment

metadata:
  name: address-finder-deployment
  labels:
    app: address-finder

spec:
  replicas: 1
  selector:
    matchLabels:
      app: address-finder
  template:
    metadata:
      labels:
        app: address-finder
    spec:
      containers:
        - name: go
          image: you/address-finder-go:latest
        - name: nginx
          image: nginx:1.19.4-alpine
          ports:
            - containerPort: 8080
          volumeMounts:
            - name: nginx-config
              mountPath: /etc/nginx/conf.d/default.conf
              subPath: nginx.conf
              readOnly: true
      volumes:
        - name: nginx-config
          configMap:
            name: address-finder-config

configmap.yaml

关于configmap,你需要知道的是,这里的改变不会重启pod,所以你必须自己处理重启,这不是本篇文章的范围。

apiVersion: v1
kind: ConfigMap

metadata:
  name: address-finder-config

data:
  nginx.conf: |
    server {
      listen 8080 default_server;

      location / {
        proxy_pass http://127.0.0.1:9090/;
      }
    }

service.yaml

apiVersion: v1
kind: Service

metadata:
  name: address-finder-service

spec:
  type: NodePort
  selector:
    app: address-finder
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080

Dockerfile (go)

#
# STAGE 1: build
#
FROM golang:1.15-alpine3.12 as build

WORKDIR /source
COPY . .

RUN CGO_ENABLED=0 go build -ldflags "-s -w" -o bin/main main.go

#
# STAGE 2: run
#
FROM alpine:3.12 as run

COPY --from=build /source/bin/main /main

ENTRYPOINT ["/main"]

Dockerfile (nginx)

FROM nginx:1.19.4-alpine

COPY docker/dev/nginx/default.conf /etc/nginx/conf.d/default.conf

EXPOSE 8080

default.conf

server {
    listen 8080 default_server;
 
    location / {
        proxy_pass http://address-finder-go:9090/;
    }
}

docker-compose.yaml

version: "3.4"

services:

  address-finder-go:
    container_name: "address-finder-go"
    build:
      context: "../.."
      dockerfile: "docker/dev/go/Dockerfile"

  address-finder-nginx:
    container_name: "address-finder-nginx"
    build:
      context: "../.."
      dockerfile: "docker/dev/nginx/Dockerfile"
    ports:
        - "80:8080"
    depends_on:
        - "address-finder-go"

main.go

package main

import (
   "log"
   "net/http"
)

func main() {
   http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
      _, _ = w.Write([]byte(r.Header.Get("X-Request-Id") + "\n"))
   })

   log.Println("go server is running on :9090")
   log.Fatal(http.ListenAndServe(":9090", nil))
}

制作文件

docker-rundocker-test 命令是针对你的本地环境的。你可以用它们在本地环境中测试你的应用程序。

## Build and run.
.PHONY: docker-run
docker-run:
   docker-compose -f docker/dev/docker-compose.yaml build --no-cache
   docker-compose -f docker/dev/docker-compose.yaml up

## Remove.
.PHONY: docker-down
docker-down:
   docker-compose -f docker/dev/docker-compose.yaml down
   docker system prune --volumes --force

## Build, tag and push application image to registry then clean up.
.PHONY: docker-push
docker-push:
   docker build -t you/address-finder-go:latest -f ./docker/dev/go/Dockerfile .
   docker push you/address-finder-go:latest
   docker rmi you/address-finder-go:latest
   docker system prune --volumes --force

## Build and run.
.PHONY: docker-test
docker-test:
   curl --request GET 'http://localhost:80' --header 'X-Request-Id: my-request-id'

## -----------------------------------------------------------------------------------

## Apply secret and deploy application to kubernetes cluster.
.PHONY: k8s-deploy
k8s-deploy:
   kubectl apply -f deploy/k8s/configmap.yaml
   kubectl apply -f deploy/k8s/deployment.yaml
   kubectl apply -f deploy/k8s/service.yaml

## Send a dummy request to the exposed pod on kubernetes.
.PHONY: k8s-test
k8s-test:
   curl --request GET $(shell minikube service address-finder-service --url) --header 'X-Request-Id: my-request-id'

测试

Docker

让我们在本地环境中测试我们的应用程序,看看它是否工作:

$ make docker-run
Recreating address-finder-go ... done
Recreating address-finder-nginx ... done
address-finder-go       | 2020/11/15 21:50:14 go server is running on :9090
address-finder-nginx    | /docker-entrypoint.sh: Configuration complete; ready for start up
$ make docker-test
curl --request GET 'http://localhost:80' --header 'X-Request-Id: my-request-id'
my-request-id

现在让我们构建并推送我们的Docker镜像到Docker Hub。这个镜像将在我们运行部署时被调用,所以它很重要。

$ make push
docker build -t you/address-finder-go:latest -f ./docker/dev/go/Dockerfile .
Sending build context to Docker daemon  7.762MB
.......

部署

$ make k8s-deploy
kubectl apply -f deploy/k8s/configmap.yaml
configmap/address-finder-config created
kubectl apply -f deploy/k8s/deployment.yaml
deployment.apps/address-finder-deployment created
kubectl apply -f deploy/k8s/service.yaml
service/address-finder-service created

让我们检查一下ConfigMap和Pod的细节:

$ kubectl describe configmap address-finder-config
Name:         address-finder-config
Namespace:    default
Labels:       
Annotations:  ...

Data
====
nginx.conf:
----
server {
  listen 8080 default_server;

  location / {
    proxy_pass http://127.0.0.1:9090/;
  }
}
$ kubectl get pods
NAME                                         READY   STATUS    RESTARTS   AGE
address-finder-deployment-68dd5b79b8-m6sgd   2/2     Running   0          110s

$ kubectl logs address-finder-deployment-68dd5b79b8-m6sgd go
2020/11/15 22:15:17 go server is running on :9090

$ kubectl logs address-finder-deployment-68dd5b79b8-m6sgd nginx
/docker-entrypoint.sh: Configuration complete; ready for start up

让我们不要在Kubernetes中测试,看看日志:

$ make k8s-test
curl --request GET http://192.168.99.100:31615 --header 'X-Request-Id: my-request-id'
my-request-id
172.17.0.1 - - [15/Nov/2020:22:20:57 +0000] "GET / HTTP/1.1" 200 14 "-" "curl/7.54.0" "-"