K8s部署PHP项目
K8s部署laravel项目
前言
前端时间PHP项目部署升级需要 ,需要把Laravel开发的项目部署K8s上,下面以laravel项目为例,讲解采用yaml文件方式部署项目。
一、部署步骤
1.创建Dockerfile文件
Dockerfile是一个用来构建镜像的文本文件,在容器运行时,需要把项目文件和项目运行所必须的组件安装其中。
# 基础镜像
FROM php:7.4-fpm
# 时区
ARG TZ=Asia/Shanghai
# 更换容器时区
RUN cp "/usr/share/zoneinfo/$TZ" /etc/localtime && echo "$TZ" > /etc/timezone
# 替换成阿里apt-get源
RUN sed -i "s@http://deb.debian.org@http://mirrors.aliyun.com@g" /etc/apt/sources.list && rm -rf /var/lib/apt/lists/* && cat /etc/apt/sources.list
# 调试扩展
# vim net-tools rsyslog procps
# 安装扩展
RUN apt-get update \
&& apt-get install -y libzip-dev zip libfreetype6-dev libjpeg62-turbo-dev libmcrypt-dev librdkafka-dev libpng-dev cron supervisor \
&& rm -rf /var/lib/apt/lists/* \
&& docker-php-ext-configure gd \
&& docker-php-ext-install -j$(nproc) gd mysqli pdo_mysql zip opcache bcmath iconv
# 安装kafka扩展
COPY deploy/docker/php/ext/rdkafka-5.0.0.tgz /tmp/
RUN pecl install /tmp/rdkafka-5.0.0.tgz && docker-php-ext-enable rdkafka
# 安装redis扩展
COPY deploy/docker/php/ext/redis-5.3.4.tgz /tmp/
RUN pecl install /tmp/redis-5.3.4.tgz && docker-php-ext-enable redis
# 创建supervisor日志目录、项目目录
RUN mkdir -p /var/log/supervisor && mkdir -p /www
# supervisor配置文件
COPY deploy/docker/supervisor/conf.d /etc/supervisor/conf.d
# 替换php配置文件
COPY ./deploy/docker/php/conf.d/opcache.ini /usr/local/etc/php/
COPY ./deploy/docker/php/conf.d/phpcustom.ini /usr/local/etc/php/
# CPOY定时任务
COPY deploy/docker/cron/root /var/spool/cron/crontabs
RUN chmod 600 /var/spool/cron/crontabs/root
# 安装composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
&& ln -s $(composer config --global home) /root/composer \
&& composer config -g repo.packagist composer https://packagist.phpcomposer.com
# COPY项目到/www目录
COPY . /www
# 进入/www目录
WORKDIR /www
# 删除多余文件
RUN rm -rf $(find /www/backend/ -maxdepth 1 ! -name "backend" ! -name "dist") && rm -rf /tmp/*
# /www下文件授权用户组和用户权限;composer安装需要包(如果项目composer存在,可不执行)
RUN chown -R www-data:www-data /www/storage \
&& composer install \
--optimize-autoloader \
--ignore-platform-reqs \
--prefer-dist \
--no-interaction \
--no-dev
# 执行entrypoint
COPY deploy/docker/entrypoint.sh /usr/local/bin/entrypoint
RUN chmod +x /usr/local/bin/entrypoint
ENTRYPOINT ["/usr/local/bin/entrypoint"]
2. 创建命名空间【namespace.yaml】
Kubernetes使用命名空间的概念帮助解决集群中在管理对象时的复杂性问题。命名空间允许将对象分组到一起,便于将它们作为一个单元进行筛选和控制;简单理解可以实现项目彼此隔离。
- 创建Namespace
kubectl create -f namespace.yaml
- 查看所有Namespace
kubectl get namespaces
apiVersion: v1 #版本号
kind: Namespace #配置类型
metadata: #元数据
name: php-service #该 Namespace 的名称
3. 创建App Env Config【app-env-config.yaml】(laravel .env 配置)
- 创建App Env Config
kubectl create -f app-env-config.yaml
- 查看该命名空间所有Config
kubectl get --namespace=php-service configmaps
- 查看该Config
kubectl get --namespace=php-service configmaps app-env-config
- 查看该Conifg Yaml
kubectl get --namespace=php-service configmaps app-env-config -o yaml
apiVersion: v1 #版本号
kind: ConfigMap #配置类型
metadata: #元数据
name: app-env-config #该 ConfigMap 的名称
namespace: php-service #该 ConfigMap 所在命名空间
data: #该 ConfigMap 数据
# App Config
APP_DEBUG: 'true'
APP_ENV: test
APP_KEY: xxx
# DB Config
DB_DATABASE: xxx
DB_HOST: xx.xx.xx.xx
DB_PASSWORD: xxx
DB_USERNAME: xxx
# JWT Config
JWT_KEY: XXX
JWT_SECRET: XXX
JWT_TOKEN_EXPIRE_TIME: '86400'
# Redis Config
REDIS_DATABASE: '0'
REDIS_HOST: xx.xx.xx.xx
REDIS_PASSWORD: xxx
REDIS_PORT: '6380'
REDIS_PREFIX: xxx
4. 创建Nginx Config【nginx-config.yaml】
- 创建Nginx Config
kubectl create -f nginx-config.yaml
- 查看该创建Config
kubectl get --namespace=php-service configmaps
- 查看该Conifg Yaml
kubectl get --namespace=php-service configmaps nginx-config -o yaml
apiVersion: v1 #版本号
kind: ConfigMap #配置类型
metadata: #元数据
name: nginx-config #该 ConfigMap 的名称
namespace: php-service #该 ConfigMap 所在命名空间
data: #数据
nginx_conf: |-
user www-data;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name _;
root /var/www/html/public;
index index.php;
#charset koi8-r;
#access_log /var/log/nginx/log/host.access.log main;
#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;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
location ~ \.php$ {
include fastcgi_params;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
}
location /backend/ {
index index.html;
alias /var/www/html/backend/dist/;
}
location /statics/{
alias /var/www/html/backend/dist/statics/;
}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
}
5. 创建Nginx Service【nginx-service.yaml】
- 创建Nginx Service
kubectl create -f nginx-service.yaml
- 查看该Service
kubectl get --namespace=php-service service -o wide
- 查看该Service Yaml
kubectl get --namespace=php-service service nginx-service -o yaml
apiVersion: v1 #版本号
kind: Service #配置类型
metadata: #元数据
name: nginx-service #该Service 的名称
namespace: php-service #该 Service 所在命名空间
labels: #标签
app: nginx #为该 Service 设置 key 为 app,value 为 nginx 的标签
spec: #关于该 Service 的定义,描述了 Service 如何选择 Pod,如何被访问
selector: #标签选择器
app: kayaka #选择包含标签 app:kayaka 的Pod
type: NodePort #Serive的类型,ClusterIP/NodePort/LoaderBalancer
ports:
- name: http #端口的名字
protocol: TCP #协议类型 TCP/UDP
port: 80 #集群内的其他容器组可通过 80 端口访问 Service
#port: 30080 #通过任意节点的 32600 端口访问 Service,不固定自动设置
targetPort: 80 #将请求转发到匹配 Pod 的 80 端口
6. 创建App Deployment【app-deployment.yaml】(主要采用 POD-容器组(php-fpm和nginx)的方式)
- 创建App Deployment
kubectl apply -f app-deployment.yaml
- 查看该命名空间所有Deployment
kubectl get --namespace=php-service deployments -o wide
- 查看该Deployment
kubectl get --namespace=php-service deployments kayaka -o wide
- 查看该Deployment Yaml
kubectl get --namespace=php-service deployments kayaka -o yaml
apiVersion: apps/v1 #与k8s集群版本有关,使用 kubectl api-versions 即可查看当前集群支持的版本
kind: Deployment #配置类型,这里使用的是 Deployment
metadata: #元数据,即 Deployment 的一些基本属性和信息
name: kayaka #该Deployment 的名称
namespace: php-service #Pod所属的命名空间
labels: #标签,可以灵活定位一个或多个资源,其中key和value均可自定义,可以定义多组
app: kayaka #为该Deployment设置key为app,value为nginx的标签
spec: #该Deployment的描述,可以理解为你期待该Deployment在k8s中如何使用
selector: #标签选择器,与上面的标签共同作用,目前不需要理解
matchLabels: #选择包含标签app:kayaka的资源
app: kayaka
replicas: 2 #使用该Deployment创建几个应用程序实例
strategy: #更新策略
type: RollingUpdate #Recreate 重新创建 RollingUpdate 滚动升级
template: #选择或创建的Pod的模板
metadata: #Pod的元数据
labels: #Pod的标签,上面的selector即选择包含标签app:kayaka的Pod
app: kayaka
spec: #期望Pod实现的功能(即在pod中部署)
containers: #生成container,与docker中的container是同一种
- name: kayaka #container的名称
image: harbor.dobest.com/tfctest/kayaka:1.0.0 #镜像地址
imagePullPolicy: Always #镜像拉取策略 Always 总是拉去、IfNotPresent 优先使用本地、Never 仅使用本地
ports: #容器端口
- containerPort: 9000
#env:
#- name: REDIS_HOST
#value: redis-service
envFrom: #ENV 配置来源(无法热更新)
- configMapRef:
name: app-env-config
volumeMounts: #挂载到容器内部的存储卷配置
- name: nginx-www #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
mountPath: /var/www/html #存储卷在容器内mount的绝对路径
readOnly: false #是否为只读模式
lifecycle: #container 的生命周期
postStart: #容器开始启动执行事件
exec:
command: [ "/bin/sh","-c","cp -r /www/* /var/www/html && chown -R www-data:www-data /var/www/html/storage" ]
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
volumeMounts:
- mountPath: /var/www/html
name: nginx-www
- mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
name: nginx-config
volumes: #该pod上定义共享存储卷列表
- name: nginx-www #共享存储卷名称 (volumes类型有很多种)
emptyDir: { } #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
- name: nginx-config #共享存储卷名称(volumes类型有很多种)
configMap: #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
name: nginx-config
items:
- key: nginx_conf
path: nginx.conf
7. 创建Ingress【ingress.yaml】路由
- 创建Ingress
kubectl apply -f ingress.yaml
- 查看该命名空间所有Ingress
kubectl get --namespace=php-service ingress -o wide
- 查看该Ingress
kubectl get --namespace=php-service ingress ingress
- 查看该Ingress Yaml
kubectl get --namespace=php-service ingress ingress -o yaml
apiVersion: extensions/v1beta1 #版本号
kind: Ingress #配置类型
metadata: #元数据
name: ingress #该 Ingress 的名称
namespace: php-service #该 Ingress 所在命名空间
labels: #标签
app: ingress
spec: #该 Ingress 的描述
rules: # 规则
- host: test-kyk.sanguosha.com # 域名
http:
paths: # 路径
- backend:
serviceName: nginx-service #服务名称
servicePort: 80 #服务端口
path: /
注意事项
- 更新 ConfigMap
- 使用该 ConfigMap 挂载的 Env 不会同步更新
- 使用该 ConfigMap 挂载的 Volume 中的数据需要一段时间(实测大概10秒)才能同步更新
- ENV 是在容器启动的时候注入的,启动之后 kubernetes 就不会再改变环境变量的值,且同一个 namespace 中的 pod 的环境变量是不断累加的,为了更新容器中使用 ConfigMap 挂载的配置,可以通过滚动更新 pod 的方式来强制重新挂载 ConfigMap
- 定时任务问题
- 当Pod个数大于1时,每个Pod中容器都存在定时任务,为了避免定时任务冲突,可以使用Redis分布式锁,使定时任务在其中一个Pod中执行。
- 项目日志问题
- laravel日志默认写入文件,日志写入pod中,我们也可创建存储类,但查看日志又存在问题,所以建议写入kafka中,再去消费处理日志。
更多推荐
所有评论(0)