Kubernetes (K8S) as the most popular container arrangement management tool, has gradually been the operation and maintenance of major enterprises as the preferred scheme, container deployment application scheme based on K8S is also more and more. Some time ago also found time to learn this technology, with two words: really fragrant.
However, as a small business developer, there will inevitably be trouble in using K8S. That is, the default open port of K8S is 3000-32767. If you use NodePort as an external access solution, you need to use the domain name /IP with the number of the upper end, which is very ugly. LodaBalance’s solution relies on the load balancers of the major carriers, which is a costly tool, so how to access your own service directly through a domain name without ports becomes a major focus.
What is the cause of the problem?
K8S opens port 3000-32767 by default, so there is no specified HTTP(S) port other than 80 or 443 when the service is released. As a result, when we access the corresponding service, we need to specify the port number after the domain name and IP to access. As an obsessive-compulsive program, we hope to solve this problem.
solution
Ports 80 and 443 are Web servers, so consider using a reverse proxy to access the service.
Thought analysis
Based on the above ideas, I came up with two solutions:
1. Use the NGINX server as a reverse proxy
Advantages: 1, simple, fast, as long as you can write nginx configuration files can be implemented 2, more general, independent deployment of a nginx is equivalent to doing your own load balancer, for later extension and migration are very convenient disadvantages: 1, because of the separation from the control of K8S, so if there is a problem with the service, it needs to independently monitor and maintain, and management is complicated. 2, independent deployment requires independent maintenance of a set of configuration, which is quite complicatedCopy the code
2. Deploy ingress-nginx on K8S for reverse proxy
Ingress-nginx is deployed on top of K8S, so K8S can monitor the operation of the service itself. It is easy to manage a set of YAML files to complete the deployment of multiple domain names. If ingress-nginx is used to access ports 80 and 443, it must be bound to the corresponding host, so that the service itself cannot be separated from the host port. If the ingress-nginx host is down, the migration cannot be normal, and kubernetes retry mechanism is not availableCopy the code
Implementation method
Nginx can be installed as a reverse proxy, or docker can be installed as a reverse proxy
I used Docker to install it
On the host to create a directory to store the content of the nginx # mkdir -p/root/docker/nginx/conf. # d mkdir -p/root/docker/nginx/HTML # mkdir -p / root/docker/nginx/log run a docker command # docker run - d - v/root/docker/nginx/conf., d/a: / etc/nginx/conf. D/v /root/docker/nginx/html/:/usr/share/nginx/html -v /root/docker/nginx/logs/:/var/log/nginx -p 80:80 -p 443:443 --name=nginx --restart=always --privileged=true # docker ps mingl # docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3AE5fb0347E8 nginx "/ docker-entryPoint...." 3 weeks ago Up 7 days 0.0.0.0:80->80/ TCP, :::80->80/ TCP, 0.0.0.0:443->443/ TCP, :::443->443/ TCP Nginx configuration is complete.Copy the code
Conf file in /etc/nginx, which contains all *. Conf files in conf. D, so there is no need to add a separate HTTP layer. So I didn’t use HTTP {} in subsequent configuration files.
Here is a configuration file to introduce:
In the/root/docker/nginx/conf. D/below, create a console. The conf file
Upstream console {server ip1:port1; server ip2:port2; } ## rewrite server {listen 80; / / rewrite server {listen 80; Server_name Specifies the domain name. rewrite ^(.*)$ https://$host$1; # redirect all HTTP requests via the rewrite directive to HTTPS #location / {# proxy_pass http://console; # proxy_redirect off; # proxy_set_header Host $host; # proxy_set_header X-Real-IP $remote_addr; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # proxy_set_header X-Forwarded-Proto $scheme; # proxy_set_header Upgrade $http_upgrade; # proxy_set_header Connection $connection_upgrade; # proxy_set_header X-Request-ID $request_id; # proxy_next_upstream error timeout; # proxy_http_version 1.1; If you want to create a cert directory on the host conf.d file, you can create a cert directory on the host conf.d file. My certificate is under host/root/docker/nginx/conf. # # because under d/cert as container mapping is - v/root/docker/nginx/conf., d/a: / etc/nginx/conf. D / # # So ssl_certificate and ssl_certificate_key configuration will be written below # # ssl_certificate/etc/nginx/conf. D/XXX. Pem; ## ssl_certificate_key /etc/nginx/conf.d/xxx.key server { listen 443 ssl; Ssl_certificate Specifies the path to the SSL pem certificate file. Ssl_certificate_key Specifies the directory for storing the KEY certificate for SSL. ssl_session_timeout 5m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:! NULL:! aNULL:! MD5:! ADH:! RC4; # indicates the type of cipher suite used. Ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # indicates the type of TLS protocol used. ssl_prefer_server_ciphers on; gzip on; gzip_min_length 1k; gzip_buffers 4 16k; # gzip_http_version 1.0; gzip_comp_level 2; gzip_types text/plain application/javascript application/x-javascript text/javascript application/json text/css application/xml application/x-httpd-php image/jpeg image/gif image/png; gzip_vary off; gzip_disable "MSIE [1-6]\."; Server_name Specifies the domain name. location / { proxy_pass http://console; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header X-Request-ID $request_id; proxy_next_upstream error timeout; Proxy_http_version 1.1; }} In addition, the HTTPS certificate must be the same as server_name for authentication.Copy the code
In this way, nginx’s reverse proxy can be used to proxy our container’s services, which can be accessed by directly accessing the domain name
Scheme 2: Use ingress-nginx to perform reverse proxy processing
Install ingress-nginx on k8S:
Nginx-ingress-controller official documentation
# curl -O https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.1.0/deploy/static/provider/cloud/deploy.yaml
Copy the code
Download the deployment file from above
2, need to modify the file through VIm
## 找到文件Deployment的位置,将类型kind改成DaemonSet
# Source: ingress-nginx/templates/controller-deployment.yaml
apiVersion: apps/v1
kind: Deployment ==> DaemonSet
metadata:
labels:
helm.sh/chart: ingress-nginx-4.0.10
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/version: 1.1.0
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/component: controller
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: controller
revisionHistoryLimit: 10
minReadySeconds: 0
template:
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: controller
spec:
dnsPolicy: ClusterFirst
hostNetwork: true # 在spec下设置hostNetwork设置为true,如果没有就自行添加,绑定主机网络,先保证物理机上的80和443没有被占用
containers:
- name: controller
image: k8s.gcr.io/ingress-nginx/controller:v1.1.0@sha256:f766669fdcf3dc26347ed273a55e754b427eb4411ee075a53f30718b4499076a # 因为k8s.gcr.io是google的服务器,如果有科学上网则不需要改image
# image: image: registry.aliyuncs.com/google_containers/nginx-ingress-controller:v1.1.0
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
args:
- /nginx-ingress-controller
- --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
- --election-id=ingress-controller-leader
- --controller-class=k8s.io/ingress-nginx
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
runAsUser: 101
allowPrivilegeEscalation: true
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: LD_PRELOAD
value: /usr/local/lib/libmimalloc.so
livenessProbe:
failureThreshold: 5
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 1
ports:
- name: http
containerPort: 80
protocol: TCP
- name: https
containerPort: 443
protocol: TCP
- name: webhook
containerPort: 8443
protocol: TCP
volumeMounts:
- name: webhook-cert
mountPath: /usr/local/certificates/
readOnly: true
resources:
requests:
cpu: 100m
memory: 90Mi
nodeSelector:
kubernetes.io/os: linux
serviceAccountName: ingress-nginx
terminationGracePeriodSeconds: 300
volumes:
- name: webhook-cert
secret:
secretName: ingress-nginx-admission
此处的两个也是同样的替换镜像文件,科学上网忽略
---
# Source: ingress-nginx/templates/admission-webhooks/job-patch/job-createSecret.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: ingress-nginx-admission-create
namespace: ingress-nginx
annotations:
helm.sh/hook: pre-install,pre-upgrade
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
labels:
helm.sh/chart: ingress-nginx-4.0.10
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/version: 1.1.0
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/component: admission-webhook
spec:
template:
metadata:
name: ingress-nginx-admission-create
labels:
helm.sh/chart: ingress-nginx-4.0.10
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/version: 1.1.0
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/component: admission-webhook
spec:
containers:
- name: create
image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660
# image: registry.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.0
imagePullPolicy: IfNotPresent
args:
- create
- --host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
- --namespace=$(POD_NAMESPACE)
- --secret-name=ingress-nginx-admission
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
securityContext:
allowPrivilegeEscalation: false
restartPolicy: OnFailure
serviceAccountName: ingress-nginx-admission
nodeSelector:
kubernetes.io/os: linux
securityContext:
runAsNonRoot: true
runAsUser: 2000
---
# Source: ingress-nginx/templates/admission-webhooks/job-patch/job-patchWebhook.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: ingress-nginx-admission-patch
namespace: ingress-nginx
annotations:
helm.sh/hook: post-install,post-upgrade
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
labels:
helm.sh/chart: ingress-nginx-4.0.10
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/version: 1.1.0
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/component: admission-webhook
spec:
template:
metadata:
name: ingress-nginx-admission-patch
labels:
helm.sh/chart: ingress-nginx-4.0.10
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/version: 1.1.0
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/component: admission-webhook
spec:
containers:
- name: patch
image: k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660
# image: registry.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.0
imagePullPolicy: IfNotPresent
args:
- patch
- --webhook-name=ingress-nginx-admission
- --namespace=$(POD_NAMESPACE)
- --patch-mutating=false
- --secret-name=ingress-nginx-admission
- --patch-failure-policy=Fail
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
securityContext:
allowPrivilegeEscalation: false
restartPolicy: OnFailure
serviceAccountName: ingress-nginx-admission
nodeSelector:
kubernetes.io/os: linux
securityContext:
runAsNonRoot: true
runAsUser: 2000
Copy the code
After the configuration file is modified, run commands to install it
# kubect apply -f deploy.yaml
Copy the code
How do I determine the installation is complete
RESTARTS AGE ingress-nginx NAME RESTARTS AGE ingress-nginx-admission create-r2fdf 0/1 kubectl get pod -n ingress-nginx NAME RESTARTS AGE ingress-nginx-admission create-r2fdf 0/1 Completed 0 3h9m ingress-nginx-admission-patch-pw84m 0/1 Completed 1 3h9m ingress-nginx-controller-6dt7g 1/1 Running 0 Ingress-nginx-controller-xxxx is Running and READY is 1/1Copy the code
At this point, you access port 80 on the target machine
If a 404 not found appears, it is normal.
We then create a Tomcat deployment service under default :tomcat-deployment.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
name: tomcat
namespace: default
labels:
app: tomcat
annotations:
deployment.kubernetes.io/revision: '1'
kubesphere.io/creator: admin
spec:
replicas: 1
selector:
matchLabels:
app: tomcat
template:
metadata:
creationTimestamp: null
labels:
app: tomcat
spec:
volumes:
- name: host-time
hostPath:
path: /etc/localtime
type: ''
containers:
- name: container-b0zpfy
image: 'tomcat:jre8'
ports:
- name: tcp-8080
containerPort: 8080
protocol: TCP
resources: {}
volumeMounts:
- name: host-time
readOnly: true
mountPath: /etc/localtime
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
imagePullPolicy: IfNotPresent
restartPolicy: Always
terminationGracePeriodSeconds: 30
dnsPolicy: ClusterFirst
serviceAccountName: default
serviceAccount: default
securityContext: {}
affinity: {}
schedulerName: default-scheduler
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%
revisionHistoryLimit: 10
progressDeadlineSeconds: 600
Copy the code
Create a Service Service for tomcat: tomcat-svc.yaml
kind: Service
apiVersion: v1
metadata:
name: tomcat
namespace: default
labels:
app: tomcat
annotations:
kubesphere.io/creator: admin
spec:
ports:
- name: http-8080
protocol: TCP
port: 8080
targetPort: 8080
selector:
app: tomcat
type: ClusterIP
sessionAffinity: None
Copy the code
Create a tomcat-ingress.yaml file
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-app-ingress-tomcat
spec:
rules:
- host: www.tomcat1.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tomcat
port:
number: 8080
ingressClassName: nginx
Copy the code
Kubectl apply-f is executed separately in the above order to launch the files
# kubectl get pods -n default NAME READY STATUS RESTARTS AGE tomcat-54d6dc4796-llrzl 1/1 Running 0 3h7m # kubectl get SVC -n default NAME TYPE cluster-ip external-ip PORT(S) AGE Tomcat ClusterIP 10.233.22.156 < None > 8080/TCP 5M59s # kubectl get ing -n default NAME CLASS HOSTS ADDRESS PORTS AGE nginx-app-ingress-tomcat nginx www.tomcat2.com 80, 443 2m47sCopy the code
Run the preceding three commands to check whether the service is started
After the startup was completed, I saw that the HOSTS of ingress was www.tomcat2.com, because there was no domain name I, so I changed the local host to do the mapping
Then access the domain name through your browser
The current page is displayed, this is not the same as the nginx style exception page, is tomcat 404, indicating that we successfully accessed the Tomcat service through the domain name
At this point, both schemes are demonstrated
extension
1. Ingress-nginx adds HTTPS certificate non-self-signed certificate, puts the certificate on the server, and generates certificate secret from the command line
--from-file=tls. CRT = path where the CRT key is located --from-file=tls.key= path where the key is located # kubectl -n demo-echo create secret generic www-tomcat-com --from-file=tls.crt=server.crt --from-file=tls.key=server.keyCopy the code
Then add the TLS configuration in the tomcat-ingress.yaml file
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nginx-app-ingress spec: rules: - host: www.tomcat.com http: paths: - path: / pathType: Prefix backend: service: name: tomcat port: number: 8080 tls: - hosts: SecretName: WWW -tomcat-com # The name of the secret key ingressClassName: nginxCopy the code
The deployment will then be able to access the service via HTTPS, which will not be shown in screenshots.
The generation scheme of self-signed certificate is attached:
Echo "Generate a self-signed CA certificate" openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca. CRT -days 3560 -nodes -subj '/CN=My Cert Authority' echo "openssl req -new-newkey rsa:4096 -keyout server.key -out Csr-nodes -subj '/CN=www.tomcat.com' Here /CN= domain name Write your own domain name openssl x509 -req -sha256 -days 3650 -in server.csr-ca ca.crt -CAkey ca.key -set_serial 01 -out server.crtCopy the code
2. During the operation, I tried to access services in different namespaces, but the execution failed
Error from server (InternalError): error when creating "tomcat-ingress.yaml": Internal error occurred: failed calling webhook "validate.nginx.ingress.kubernetes.io": the server rejected our request for an unknown reason
Copy the code
This exception is currently given by removing ingress-nginx-admission
# # # to perform the following command kubectl delete - A ValidatingWebhookConfiguration ingress - nginx - admissionCopy the code
Can be normal, the specific reason should be because of the permission problem
conclusion
There are two kinds of problems with k8S requiring port access
Personally, I prefer the first one, although the second one is elegant, but the first one is relatively conventional, suitable for most scenarios, good operation and maintenance can maintain these things, of course, if it is not poor money, the most recommended LoadBalance of course, which saves the trouble of operation and maintenance (hair less 🙂 smile).
Welcome to teach each other, exchange learning. If it is helpful, please send a “like”
Reference links:
Resolve ingress cross-namespace access
Set the self-signed certificate and ingress HTTPS deployment
Ingress-nginx deploys port 80/443