**前置文章:**[二进制安装Kubernetes 1.20.4](https://www.xiaoleizhang.com/index.php/archives/186/ "二进制安装Kubernetes 1.20.4") **前置文章:**[CentOS 7.9 NFS服务搭建与配置](https://www.xiaoleizhang.com/index.php/archives/191/ "CentOS 7.9 NFS服务搭建与配置") **环境配置** |IP地址 |操作系统 | 机器角色 | | :------------: | :------------: | :------------: | :------------: | :------------: | :------------: | |192.168.1.21 |CentOS 7.9 | master1 | |192.168.1.22 |CentOS 7.9 | node1 | |192.168.1.23 |CentOS 7.9 | node2 | |192.168.1.31 |CentOS 7.9 |NFS服务端 | ------------ ------------ **LNMP** 代表的就是: Linux系统下Nginx+MySQL+PHP这种网站服务器架构。 我这里试着把我的博客网站部署到Kubernetes,下面是我的详细步骤 # 一、部署NFS 我们这里使用NFS来放持久化数据,NFS可以用于多个Pod或多个Node之间的数据存储和共享。 具体的可以参考这篇文章部署 **[CentOS 7.9 NFS服务搭建与配置](https://www.xiaoleizhang.com/index.php/archives/191/ "CentOS 7.9 NFS服务搭建与配置")** # 二、部署PV **PersistentVolume(PV)**就可以理解为是一个网络存储,就是一个实实在在的存储数据的地方,只不过是以网络的方式发生数据到存储的地方,比如NFS, iSCSI和云提供商指定的存储系统。 若严格来说,PV是Kubernetes里面的一个概念,它本身不是存储,只不过是创建pv的资源清单文件中指定了网络存储的地址,同时也指定了一些存储的参数,例如一些大小,性能等指标。 可以先创建个目录,专门放yaml文件 ```shell [root@master1 ~]# mkdir /home/yaml [root@master1 ~]# cd /home/yaml/ [root@master1 yaml]# vim blog-pv.yaml ``` blog-pv.yaml的具体内容如下 ```yaml apiVersion: v1 kind: PersistentVolume metadata: name: pv-mysql spec: capacity: storage: 3Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain storageClassName: nfs-mysql nfs: path: /nfs/mysql server: 192.168.1.31 --- apiVersion: v1 kind: PersistentVolume metadata: name: pv-nginx spec: capacity: storage: 10Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain storageClassName: nfs-nginx nfs: path: /nfs/nginx server: 192.168.1.31 ``` 创建PV ```shell [root@master1 yaml]# kubectl apply -f blog-pv.yaml persistentvolume/pv-mysql created persistentvolume/pv-nginx created [root@master1 yaml]# ``` 查看已创建的PV ```shell [root@master1 yaml]# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-mysql 3Gi RWX Retain Available nfs-mysql 88s pv-nginx 10Gi RWX Retain Available nfs-nginx 88s [root@master1 yaml]# ``` # 三、部署PVC **PersistentVolumeClaim(PVC)**可以理解为Pod对所需网络存储卷需满足一定要求的一个申明。它展示了Pod想需要存储的性能指标,也就是说PVC是服务于Pod,为其寻找一个合适的PV给Pod使用。绑定之后,PVC和PV是一一对应关系。 创建yaml文件 ```shell [root@master1 yaml]# vim blog-pvc.yaml ``` blog-pvc.yaml文件内容如下 ```yaml kind: PersistentVolumeClaim apiVersion: v1 metadata: name: mysql-pvc spec: storageClassName: nfs-mysql accessModes: - ReadWriteMany resources: requests: storage: 2Gi --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: nginx-pvc spec: storageClassName: nfs-nginx accessModes: - ReadWriteMany resources: requests: storage: 8Gi ``` 创建PVC ```shell [root@master1 yaml]# kubectl apply -f blog-pvc.yaml persistentvolumeclaim/mysql-pvc created persistentvolumeclaim/nginx-pvc created [root@master1 yaml]# ``` 查看已创建的PVC ```shell [root@master1 yaml]# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE mysql-pvc Bound pv-mysql 3Gi RWX nfs-mysql 68s nginx-pvc Bound pv-nginx 10Gi RWX nfs-nginx 68s [root@master1 yaml]# ``` # 四、部署MySQL 5.7 首先创建configmap,这里主要是为了设置数据库的密码 ```shell [root@master1 yaml]# vim mysql-configmap.yaml ``` mysql-configmap.yaml内容如下 ```yaml apiVersion: v1 kind: ConfigMap metadata: name: mysql-config namespace: default data: rootpassword: 1qaz@WSX ``` 创建configmap ```shell [root@master1 yaml]# kubectl apply -f mysql-configmap.yaml configmap/mysql-config created [root@master1 yaml]# ``` 查看configmap ```shell [root@master1 yaml]# kubectl get configmaps NAME DATA AGE kube-root-ca.crt 1 24d mysql-config 1 41s [root@master1 yaml]# ``` 部署MySQL的Deployment控制器,这里不建议写多个Pod,因为我试过MySQL多个Pod共用一个存储时,会有报错,数据库连接不稳定,数据库的Pod会疯狂重启。所以建议replicas设置成 1 。 ```shell [root@master1 yaml]# vim mysql-deployment.yaml ``` mysql-deployment.yaml内容如下 ```yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: mysql name: mysql spec: replicas: 1 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - image: mysql:5.7 name: mysql ports: - containerPort: 3306 volumeMounts: - name: nfs-vol mountPath: /var/lib/mysql env: - name: MYSQL_ROOT_PASSWORD valueFrom: configMapKeyRef: name: mysql-config key: rootpassword volumes: - name: nfs-vol persistentVolumeClaim: claimName: mysql-pvc ``` 创建MySQL的Deployment控制器 ```shell [root@master1 yaml]# kubectl apply -f mysql-deployment.yaml deployment.apps/mysql created [root@master1 yaml]# ``` 查看MySQL的Deployment控制器 ```shell [root@master1 yaml]# kubectl get deployment -o wide NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR mysql 1/1 1 1 36s mysql mysql:5.7 app=mysql [root@master1 yaml]# ``` 因为我这里是迁移的,所以可以创建一个service把端口放出来,然后通过mysqldump把数据库导入导出 类似于下面这样 创建一个service把数据库的3306端口映射到Kubernetes集群节点的nodeport上去 ```shell [root@master1 yaml]# vim mysql-nodeport-service.yaml ``` mysql-nodeport-service.yaml的内容如下 ```yaml apiVersion: v1 kind: Service metadata: name: mysql-nodeport-service spec: ports: - port: 3306 nodePort: 30060 selector: app: mysql type: NodePort ``` 创建service ```shell [root@master1 yaml]# kubectl apply -f mysql-nodeport-service.yaml service/mysql-nodeport-service created [root@master1 yaml]# ``` 查看service ```shell [root@master1 yaml]# kubectl get service mysql-nodeport-service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mysql-nodeport-service NodePort 10.0.0.117 3306:30060/TCP 37s [root@master1 yaml]# ``` 然后通过与集群节点可达的MySQL客户端,把数据库数据导入即可,类似于下面的 ```shell [root@localhost ~]# mysql -u root -h 192.168.1.21 -P 30060 -p1qaz@WSX < 2022-05-08.sql ``` 然后登录上去你就能看到数据了,如果不想对外后面可以再把这个service删了,如果数据库只想对内,你还需要创建一个clusterIP的service,因为Pod的IP是会变的 ```shell [root@master1 yaml]# vim mysql-clusterIP-service.yaml ``` mysql-clusterIP-service.yaml内容如下 ```yaml kind: Service apiVersion: v1 metadata: name: mysqlclusteripservice spec: selector: app: mysql ports: - protocol: TCP port: 3306 targetPort: 3306 type: ClusterIP ``` 创建service,后查看,这里不再赘述 ```shell [root@master1 yaml]# kubectl apply -f mysql-clusterIP-service.yaml service/mysqlclusteripservice created [root@master1 yaml]# [root@master1 yaml]# kubectl get svc mysqlclusteripservice NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mysqlclusteripservice ClusterIP 10.0.0.185 3306/TCP 22s [root@master1 yaml]# ``` # 五、部署PHP 部署PHP需要注意的点如下: 1. 你使用的容器镜像是否有你所需要的php-fpm的扩展,比如我这边需要的是Pdo_Mysql这个扩展,你可以创建完成后去Pod里看下具体有的扩展是否满足你的要求。 2. 你PHP挂载的是网站的根目录,我的是/blog,里面用的就是nginx的存储。 我们依旧首先创建一个PHP的Deployment。 ```shell [root@master1 yaml]# vim php-deployment.yaml ``` php-deployment.yaml内容如下: ```yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: php name: php spec: replicas: 1 selector: matchLabels: app: php template: metadata: labels: app: php spec: containers: - image: xiaoleizhang/php-fpm:7.3-r7 name: php ports: - containerPort: 9000 name: php volumeMounts: - name: nfs-php mountPath: /blog volumes: - name: nfs-php persistentVolumeClaim: claimName: nginx-pvc ``` 创建Deployment ```shell [root@master1 yaml]# kubectl apply -f php-deployment.yaml deployment.apps/php created [root@master1 yaml]# ``` 查看创建的Deployment(镜像有点大,时间相对会长一点) ```shell [root@master1 yaml]# kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE mysql 1/1 1 1 5h42m php 1/1 1 1 110s [root@master1 yaml]# ``` 可以进入Pod内部看下有哪些php-fpm的扩展 ```shell [root@master1 yaml]# kubectl get pod NAME READY STATUS RESTARTS AGE mysql-76c69d65df-2fqhx 1/1 Running 0 5h43m php-7db4f577dd-fj9h9 1/1 Running 0 3m1s [root@master1 yaml]# [root@master1 yaml]# kubectl exec -it php-7db4f577dd-fj9h9 bash kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead. root@php-7db4f577dd-fj9h9:/# root@php-7db4f577dd-fj9h9:/# php -m [PHP Modules] apcu bcmath bz2 calendar Core ctype curl date dba dom ds enchant exif fileinfo filter ftp gd gettext gmp hash iconv igbinary imagick imap interbase intl json ldap libxml mbstring memcached mongodb msgpack mysqli mysqlnd openssl pcntl pcre PDO pdo_dblib pdo_mysql pdo_pgsql pdo_sqlite pgsql Phar posix pspell readline recode redis Reflection session shmop SimpleXML soap sockets sodium SPL sqlite3 standard sysvmsg sysvsem sysvshm tidy tokenizer wddx xml xmlreader xmlrpc xmlwriter xsl Zend OPcache zend-test zip zlib [Zend Modules] Zend OPcache root@php-7db4f577dd-fj9h9:/# ``` 同样的,我需要创建一个clusterip的service,保证ip不会改变 ```shell [root@master1 yaml]# vim php-clusterip-service.yaml ``` php-clusterip-service.yaml内容如下 ```shell apiVersion: v1 kind: Service metadata: name: php labels: app: php spec: ports: - port: 9000 selector: app: php ``` 同样的创建service以及查看 ```shell [root@master1 yaml]# kubectl apply -f php-clusterip-service.yaml service/php created [root@master1 yaml]# [root@master1 yaml]# kubectl get svc php NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE php ClusterIP 10.0.0.197 9000/TCP 35s [root@master1 yaml]# ``` # 六、部署Nginx Nginx首先根据你自己的nginx.conf配置文件创建一个configmaps,你可以先把自己的nginx.config文件上传到master1上,然后根据如下命令创建 ```shell [root@master1 yaml]# kubectl create configmap nginx-config --from-file=nginx.conf configmap/nginx-config created [root@master1 yaml]# ``` 查看创建的configmaps ```shell [root@master1 yaml]# kubectl get configmaps nginx-config NAME DATA AGE nginx-config 1 83s [root@master1 yaml]# ``` 这里我贴下,我的nginx的配置文件,需要注意的是配置文件里的路径,NFS上都需要有不然会报错,具体报错可以使用kubectl describe pod 或者 kubectl logs 去查看具体的有问题的Pod ```shell [root@master1 yaml]# cat nginx.conf # For more information on configuration, see: # * Official English Documentation: http://nginx.org/en/docs/ # * Official Russian Documentation: http://nginx.org/ru/docs/ user nginx; worker_processes auto; error_log /blog/log/nginx/error.log; pid /run/nginx.pid; # Load dynamic modules. See /usr/share/doc/nginx/README.dynamic. include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; log_format main_blog '{"@timestamp":"$time_iso8601",' '"host":"$hostname",' '"server_ip":"$server_addr",' '"client_ip":"$http_x_forwarded_for",' '"xff":"$http_x_forwarded_for",' '"domain":"$host",' '"url":"$uri",' '"referer":"$http_referer",' '"args":"$args",' '"upstreamtime":"$upstream_response_time",' '"responsetime":"$request_time",' '"request_method":"$request_method",' '"status":"$status",' '"size":"$body_bytes_sent",' '"request_body":"$request_body",' '"request_length":"$request_length",' '"protocol":"$server_protocol",' '"upstreamhost":"$upstream_addr",' '"file_dir":"$request_filename",' '"http_user_agent":"$http_user_agent"' '}'; access_log /blog/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 4096; include /etc/nginx/mime.types; default_type application/octet-stream; # Load modular configuration files from the /etc/nginx/conf.d directory. # See http://nginx.org/en/docs/ngx_core_module.html#include # for more information. include /etc/nginx/conf.d/*.conf; server { listen 80; server_name www.xiaoleizhang.com; rewrite ^(.*)$ https://$host$1 permanent; location / { root /blog; index index.html index.htm index.php; if (-f $request_filename/index.html){ rewrite (.*) $1/index.html break; } if (-f $request_filename/index.php){ rewrite (.*) $1/index.php; } if (!-f $request_filename){ rewrite (.*) /index.php; } } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } # proxy the PHP scripts to Apache listening on 127.0.0.1:80 # #location ~ \.php$ { #proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 # location ~ \.php$ { root html; fastcgi_pass 10.0.0.197:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /blog$fastcgi_script_name; include fastcgi_params; } # deny access to .htaccess files, if Apache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } server { listen 443 ssl; server_name www.xiaoleizhang.com; client_max_body_size 1000m; access_log /blog/log/blog/blog_access.log main_blog; error_log /blog/log/blog/blog_error.log; ssl_certificate /blog/crt/public.pem; ssl_certificate_key /blog/crt/private.key; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; ssl_prefer_server_ciphers on; location / { root /blog; index index.html index.htm index.php; if (-f $request_filename/index.html){ rewrite (.*) $1/index.html break; } if (-f $request_filename/index.php){ rewrite (.*) $1/index.php; } if (!-f $request_filename){ rewrite (.*) /index.php; } } location ~ \.php$ { root html; fastcgi_pass 10.0.0.197:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /blog$fastcgi_script_name; include fastcgi_params; } location ~*\.(gif|jpg|png|jpeg)$ { root /blog; valid_referers blocked www.xiaoleizhang.com; valid_referers blocked 117.50.162.102; if ($invalid_referer) { return 403; } } } # Settings for a TLS enabled server. # # server { # listen 443 ssl http2; # listen [::]:443 ssl http2; # server_name _; # root /usr/share/nginx/html; # # ssl_certificate "/etc/pki/nginx/server.crt"; # ssl_certificate_key "/etc/pki/nginx/private/server.key"; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 10m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; # # # Load configuration files for the default server block. # include /etc/nginx/default.d/*.conf; # # error_page 404 /404.html; # location = /40x.html { # } # # error_page 500 502 503 504 /50x.html; # location = /50x.html { # } # } } [root@master1 yaml]# ``` 你nginx.conf的文件里的fastcgi_pass的di地址应该是php-clusterip的地址,你连接数据库的地址也需要改下,是mysql-clusterip的地址。 紧接着我们需要创建nginx的Deployment ```shell vim nginx-deployment.yaml ``` nginx-deployment.yaml内容如下: ```yaml apiVersion: apps/v1 kind: Deployment metadata: labels: app: nginx name: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - image: nginx name: nginx ports: - containerPort: 80 name: http - containerPort: 443 name: https volumeMounts: - name: nfs-nginx mountPath: /blog - name: config-volume mountPath: /etc/nginx/nginx.conf subPath: nginx.conf volumes: - name: nfs-nginx persistentVolumeClaim: claimName: nginx-pvc - name: config-volume configMap: name: nginx-config ``` 这里我创建了3个Pod,开了80和443 接着创建这个Deployment ```shell [root@master1 yaml]# kubectl apply -f nginx-deployment.yaml deployment.apps/nginx created [root@master1 yaml]# ``` 查看所有的Pod是不是正常running了 ```shell [root@master1 yaml]# kubectl get pod -n default NAME READY STATUS RESTARTS AGE mysql-76c69d65df-2fqhx 1/1 Running 0 9h nginx-668875bf57-44gw9 1/1 Running 0 30s nginx-668875bf57-kgbdl 1/1 Running 0 30s nginx-668875bf57-kpn2m 1/1 Running 0 30s php-7db4f577dd-fj9h9 1/1 Running 0 3h42m [root@master1 yaml]# ``` 到这里基本就差不多了,接下来就是需要在集群外部访问了,这里不赘述,最简单的就是用nodeport-service的方式,如下所示就可以使用域名:32238的方式访问网站了(域名指向网络可达的集群节点) ```shell [root@master1 yaml]# cat nginx-nodeport-service.yaml apiVersion: v1 kind: Service metadata: name: nginx labels: app: nginx spec: ports: - port: 443 selector: app: nginx type: NodePort sessionAffinity: ClientIP [root@master1 yaml]# [root@master1 yaml]# kubectl get svc nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx NodePort 10.0.0.132 443:32238/TCP 11d [root@master1 yaml]# ``` ![Kubernetes 1.20.4 部署 LNMP 环境通过nodeport访问网站.png](https://www.xiaoleizhang.com/usr/uploads/2022/05/2297706343.png) **更好的办法可以参考这篇文章** [Kubernetes1.20.4 部署 Traefik2.3](https://www.xiaoleizhang.com/index.php/archives/204/ "Kubernetes1.20.4 部署 Traefik2.3") 最后修改:2022 年 05 月 10 日 © 允许规范转载 赞 1 如果觉得我的文章对你有用,请随意赞赏