分类 默认分类 下的文章

网站必须是https协议访问才有桌面通知的权限,http直接返回denied,并且移动端全面未支持桌面通知

<script type="javascript">

  // 先检查浏览器是否支持
  if (!window.Notification) {
    console.log('浏览器不支持通知');
  } else {
    // 检查用户曾经是否同意接受通知
    if (Notification.permission === 'granted') {
      var notification = new Notification(title, options); // 显示通知
    } else if (Notification.permission === 'default') {
      // 用户还未选择,可以询问用户是否同意发送通知
      Notification.requestPermission().then(permission => {
        if (permission === 'granted') {
          console.log('用户同意授权');
          var notification = new Notification(title, options); // 显示通知
        } else if (permission === 'default') {
          console.warn('用户关闭授权 未刷新页面之前 可以再次请求授权');
        } else {
          // denied
          console.log('用户拒绝授权 不能显示通知');
        }
      });
    } else {
      // denied 用户拒绝
      console.log('用户曾经拒绝显示通知');
    }

  if (Notification.permission === 'granted') {
    console.log('用户曾经同意授权');
     // 随时可以显示通知
  } else if (Notification.permission === 'default') {
    console.log('用户还未选择同意/拒绝');
    // 下一步请求用户授权
  } else {
    console.log('用户曾经拒绝授权 不能显示通知');
  }


    var option = {
        dir: 'rtl', //主体内容的水平书写顺序
        body: '通知的内容<b>html b code</b>',  //不支持html标签,实测win10长度能够显示4行文字内容,1行17个汉字
        tag: 'tag1',
        icon: 'https://maill.xxxx.com/common/images/Logo_50_0925.png', //正方形图片的地址
        data: {col1: 'test', col2: 'hello'},
        renotify: true,
        requireInteraction: true,
        silent: true, //是否无声
        sound:'',
        noscreen: false,
    }
    var notify = new Notification('我的通知的标题', option)
    notify.onshow = function(){console.log(arguments)}
    notify.onerror = function(){console.log(arguments)}
    notify.onclose = function(){console.log(arguments)}
    notify.onclick = function(){console.log(arguments);}
</script>

参数说明(摘自张鑫旭老师的博客):https://www.zhangxinxu.com/wordpress/2016/07/know-html5-web-notification/comment-page-2/#comment-414810
dir 默认值是auto, 可以是ltr或rtl,有点类似direction属性。表示提示主体内容的水平书写顺序。
lang 提示的语言。
body 提示主体内容。字符串。会在标题的下面显示
tag 字符串。标记当前通知的标签。
icon 字符串。通知面板左侧那个图标地址。
data 任意类型和通知相关联的数据。
vibrate 通知显示时候,设备震动硬件需要的振动模式。所谓振动模式,指的是一个描述交替时间的数组,分别表示振动和不振动的毫秒数,一直交替下去。例如[200, 100, 200]表示设备振动200毫秒,然后停止100毫秒,再振动200毫秒。
renotify 布尔值。新通知出现的时候是否替换之前的。如果设为true,则表示替换,相同tag属性的只会显示一个,而不会是默认的叠高楼:叠高楼
silent 布尔值。通知出现的时候,是否无声。
sound 字符串。音频地址。表示通知出现要播放的声音资源。
noscreen 布尔值。是否不再屏幕上显示通知信息。
sticky 布尔值。是否通知具有粘性,这样用户不太容易清除通知。

当浏览器最小化后,点击通知让浏览器恢复显示的方法,比如聊天页面有消息后,让用户回到浏览器

    notify.onclick = function () {
        var win = window.open();
        win.close();
    }

有时候想监测浏览器当前标签的状态,以选择使用何种通知方式(页面通知、桌面通知、浏览器标题栏提示),如下方法可以监测页面的变化

//浏览器监测标签状态,离开标签,最大最小化,都会触发这个事件,建议亲自试试以下代码
document.addEventListener("visibilitychange", function() {
  console.log( document.visibilityState );
  console.log(document.hidden);
});
//我们只需要判断  document.visibilityState  或者 document.hidden 即可知道页面是隐藏的还是显示的

在必要的时候,还有一招就是浏览器标题栏提示

//实际测试,在浏览器最小化或者标签非活动标签(切换到其它标签)时,交换时间间隔变长,或者失效
var titleInit = document.title
var isShine = true //是否提示状态
setInterval(function() {
    var title = document.title;
    if (isShine == true) {
        if (/新消息/.test(title) == false) {
            document.title = '【你有新消息】';    
        } else {
            document.title = '【     】';
        }
    } else {
        document.title = titleInit;
    }
}, 500);

notification其他细节: 摘自其它技术文章,有可能过时,仅作参考
用户拒绝显示通知:
一旦用户禁止网站显示通知,网站就不能再请求用户授权显示通知,需要用户去设置中更改。
chrome浏览器的通知设置位置:设置>高级>内容设置>通知
saafari浏览器:偏好设置>网站>通知>找到网站>修改权限/恢复默认

关闭请求权限:
在chorme浏览器中:当用户关闭请求权限的弹窗(右上角的叉叉),页面还没刷新,我们可以再次向用户请求权限。页面刷新过后,浏览器默认用户拒绝。
在safari浏览器下,没有关闭请求权限的选项,用户必须选择同意/拒绝。

icon不显示问题:
可能是网片有防盗链
safari下面不能显示icon
在safari下面,同一个网站(比如谷歌),同样的代码,chorme可以正常显示icon,safari却没有icon,也没有报错。
在stack overflow里面看到safari只支持body和tag选项,并不支持icon选项。

tag:
tag相同的通知,同时只能出现一个,老通知是否会被覆盖取决于:renotify配置和浏览器。
chrome下:当通知关闭之后,上次出现过的tag在一段时间内,不能再出现,比如刷新页面再请求相同tag的通知。(在safari下正常出现)

连续触发
在safari和chrome下短时间内连续触发通知(不设tag,不设requireInteraction),会出现如下表现:
合并为一条通知,内容只提示有XXX条通知
这个表现,通知没有icon、标题、内容,就显得没有意义了,浏览器以这种形式,限制开发者不要频繁打扰用户。

安装 docker 的步骤这里不说了,默认机器已经安装好docker

安装kubeadm、kubelet、kubectl,通过 kubeadm 创建集群
安装之前把docker安装好,hostname都配置到/etc/hosts,都添加ssl免密认证

#添加清华源
vim /etc/yum.repos.d/kubernetes.repo

[kubernetes]
name=kubernetes
baseurl=https://mirrors.tuna.tsinghua.edu.cn/kubernetes/yum/repos/kubernetes-el7-$basearch
enabled=1

#查看有没有kubeadm这个包

dnf search kubeadm

#安装包

dnf install kubeadm kubelet kubectl -y --nogpgcheck

#启用kubelet

systemctl enable kubelet

#禁用swap分区

swapoff -a
#查看分区大小是否为0
free -h

#不挂载swap分区,编辑这个文件,将swap挂载一行前缀加上#注释掉
vim /etc/fstab

#查看kudeadm配置所需的镜像名称

kubeadm config images list

#结果如下:

k8s.gcr.io/kube-apiserver:v1.21.2
k8s.gcr.io/kube-controller-manager:v1.21.2
k8s.gcr.io/kube-scheduler:v1.21.2
k8s.gcr.io/kube-proxy:v1.21.2
k8s.gcr.io/pause:3.4.1
k8s.gcr.io/etcd:3.4.13-0
k8s.gcr.io/coredns/coredns:v1.8.0

#先下载这些镜像到本地,创建一个脚本,利用阿里的镜像站下载
vim pull_k8s_config_images.sh

#!/bin/bash

#docker pull registry.aliyuncs.com/google_containers/kube-apiserver:v1.21.2
docker tag registry.aliyuncs.com/google_containers/kube-apiserver:v1.21.2 k8s.gcr.io/kube-apiserver:v1.21.2
docker rmi registry.aliyuncs.com/google_containers/kube-apiserver:v1.21.2
docker tag k8s.gcr.io/kube-apiserver:v1.21.2   192.168.1.65:5000/k8s.gcr.io/kube-apiserver:v1.21.2
docker push 192.168.1.65:5000/k8s.gcr.io/kube-apiserver:v1.21.2

docker pull registry.aliyuncs.com/google_containers/kube-controller-manager:v1.21.2  
docker tag registry.aliyuncs.com/google_containers/kube-controller-manager:v1.21.2  k8s.gcr.io/kube-controller-manager:v1.21.2
docker rmi registry.aliyuncs.com/google_containers/kube-controller-manager:v1.21.2  
docker tag k8s.gcr.io/kube-controller-manager:v1.21.2 192.168.1.65:5000/k8s.gcr.io/kube-controller-manager:v1.21.2
docker push 192.168.1.65:5000/k8s.gcr.io/kube-controller-manager:v1.21.2

docker pull registry.aliyuncs.com/google_containers/kube-scheduler:v1.21.2           
docker tag registry.aliyuncs.com/google_containers/kube-scheduler:v1.21.2           k8s.gcr.io/kube-scheduler:v1.21.2
docker rmi registry.aliyuncs.com/google_containers/kube-scheduler:v1.21.2           
docker tag k8s.gcr.io/kube-scheduler:v1.21.2    192.168.1.65:5000/k8s.gcr.io/kube-scheduler:v1.21.2
docker push 192.168.1.65:5000/k8s.gcr.io/kube-scheduler:v1.21.2

docker pull registry.aliyuncs.com/google_containers/kube-proxy:v1.21.2               
docker tag registry.aliyuncs.com/google_containers/kube-proxy:v1.21.2               k8s.gcr.io/kube-proxy:v1.21.2
docker rmi registry.aliyuncs.com/google_containers/kube-proxy:v1.21.2               
docker tag k8s.gcr.io/kube-proxy:v1.21.2    192.168.1.65:5000/k8s.gcr.io/kube-proxy:v1.21.2
docker push 192.168.1.65:5000/k8s.gcr.io/kube-proxy:v1.21.2

docker pull registry.aliyuncs.com/google_containers/pause:3.4.1                      
docker tag registry.aliyuncs.com/google_containers/pause:3.4.1                      k8s.gcr.io/pause:3.4.1
docker rmi registry.aliyuncs.com/google_containers/pause:3.4.1                      
docker tag k8s.gcr.io/pause:3.4.1   192.168.1.65:5000/k8s.gcr.io/pause:3.4.1
docker push 192.168.1.65:5000/k8s.gcr.io/pause:3.4.1

docker pull registry.aliyuncs.com/google_containers/etcd:3.4.13-0                    
docker tag registry.aliyuncs.com/google_containers/etcd:3.4.13-0                    k8s.gcr.io/etcd:3.4.13-0
docker rmi registry.aliyuncs.com/google_containers/etcd:3.4.13-0                    
docker tag k8s.gcr.io/etcd:3.4.13-0    192.168.1.65:5000/k8s.gcr.io/etcd:3.4.13-0
docker push 192.168.1.65:5000/k8s.gcr.io/etcd:3.4.13-0

#docker pull registry.aliyuncs.com/google_containers/coredns/coredns:v1.8.0           
#docker tag registry.aliyuncs.com/google_containers/coredns/coredns:v1.8.0           k8s.gcr.io/coredns/coredns:v1.8.0
#docker rmi registry.aliyuncs.com/google_containers/coredns/coredns:v1.8.0           
docker pull coredns/coredns:1.8.0
docker tag coredns/coredns:1.8.0            k8s.gcr.io/coredns/coredns:v1.8.0
docker rmi coredns/coredns:1.8.0           
docker tag k8s.gcr.io/coredns/coredns:v1.8.0    192.168.1.65:5000/k8s.gcr.io/coredns/coredns:v1.8.0
docker push 192.168.1.65:5000/k8s.gcr.io/coredns/coredns:v1.8.0

PS: 我这里是在本地有一个镜像仓库,下载回来我push到了本地的仓库,好在其它节点机器上下载包,就不走外网了,没有本地仓库不要每一个包后面两条 tag 和 push

下载镜像

chmod a+x pull_k8s_config_images.sh
./pull_k8s_config_images.sh
docker images

#开始启动kubeadm 创建集群

kubeadm init --apiserver-advertise-address=192.168.1.65 --service-cidr=10.1.0.0/16 --pod-network-cidr=10.244.0.0/16

当看到这个结果的时候,说明创建成功了,庆祝一下下吧

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.1.65:6443 --token vvrbdu.w5hc25hp418cixw9 \
    --discovery-token-ca-cert-hash sha256:e1c3ff1b568bf21114e3be23a6d93753b820ceec386b0fff0054dd9a13e901cc

按上面的提示可以部署其它节点机器,上面显示了节点机器加入集群的命令

要开始使用集群,普通用户的身份运行以下内容

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

# 配置kubetl认证信息
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
source ~/.bash_profile

或者,如果您是root用户,您可以运行

  export KUBECONFIG=/etc/kubernetes/admin.conf
  echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile

# 一定要记住这几行信息,节点加入集群需要验证
kubeadm join ......
#如果没记住,可以在master上执行下面这句,重新生成
kubeadm token create --print-join-command
**#还有个问题 token 默认有效期是24小时,失效后,node也是加不进来的。需要重新生成token
kubeadm token list # 查看当前有效的token**

# 查看一下集群pod,确认个组件都处于 Running 状态

[root@node1 ~]# kubectl get pod -n kube-system
NAME                            READY   STATUS              RESTARTS   AGE
coredns-558bd4d5db-flm5j        0/1     Pending             0          22m
coredns-558bd4d5db-rt8nd        0/1     Pending             0          22m
etcd-node1                      1/1     Running             0          22m
kube-apiserver-node1            1/1     Running             0          22m
kube-controller-manager-node1   1/1     Running             0          22m
kube-proxy-9r9zh                1/1     Running             0          22m
kube-proxy-h88jk                0/1     ContainerCreating   0          15m
kube-proxy-stljm                0/1     ContainerCreating   0          15m
kube-scheduler-node1            1/1     Running             0          22m
**#更详细的**
[root@node1 ~]# kubectl get pod --all-namespaces -o wide
NAMESPACE     NAME                            READY   STATUS              RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
kube-system   coredns-558bd4d5db-flm5j        0/1     Pending             0          25m   <none>         <none>   <none>           <none>
kube-system   coredns-558bd4d5db-rt8nd        0/1     Pending             0          25m   <none>         <none>   <none>           <none>
kube-system   etcd-node1                      1/1     Running             0          25m   192.168.1.65   node1    <none>           <none>
kube-system   kube-apiserver-node1            1/1     Running             0          25m   192.168.1.65   node1    <none>           <none>
kube-system   kube-controller-manager-node1   1/1     Running             0          25m   192.168.1.65   node1    <none>           <none>
kube-system   kube-proxy-9r9zh                1/1     Running             0          25m   192.168.1.65   node1    <none>           <none>
kube-system   kube-proxy-h88jk                0/1     ContainerCreating   0          18m   192.168.1.79   node3    <none>           <none>
kube-system   kube-proxy-stljm                0/1     ContainerCreating   0          18m   192.168.1.69   node2    <none>           <none>
kube-system   kube-scheduler-node1            1/1     Running             0          25m   192.168.1.65   node1    <none>           <none>

由于另外两个节点node2,node3没有拉取镜像,状态是ContainerCreating
#当把另两个节点从本址仓库拉取了那几个镜像之后,发现在主节点上再次执行这个命令时,看到已经是Running状态了(应该是我的三个节点之前使用docker swarm创建过集群的原因)

[root@node1 ~]# kubectl get pod --all-namespaces -o wide
NAMESPACE     NAME                            READY   STATUS    RESTARTS   AGE   IP             NODE     NOMINATED NODE   READINESS GATES
kube-system   coredns-558bd4d5db-flm5j        0/1     Pending   0          33m   <none>         <none>   <none>           <none>
kube-system   coredns-558bd4d5db-rt8nd        0/1     Pending   0          33m   <none>         <none>   <none>           <none>
kube-system   etcd-node1                      1/1     Running   0          33m   192.168.1.65   node1    <none>           <none>
kube-system   kube-apiserver-node1            1/1     Running   0          33m   192.168.1.65   node1    <none>           <none>
kube-system   kube-controller-manager-node1   1/1     Running   0          33m   192.168.1.65   node1    <none>           <none>
kube-system   kube-proxy-9r9zh                1/1     Running   0          33m   192.168.1.65   node1    <none>           <none>
kube-system   kube-proxy-h88jk                1/1     Running   0          26m   192.168.1.79   node3    <none>           <none>
kube-system   kube-proxy-stljm                1/1     Running   0          26m   192.168.1.69   node2    <none>           <none>
kube-system   kube-scheduler-node1            1/1     Running   0          33m   192.168.1.65   node1    <none>           <none>

在node2机器上面可以看到容器已经运行

[root@node2 ~]# docker ps
CONTAINER ID   IMAGE                                COMMAND                  CREATED         STATUS         PORTS      NAMES
081e6c14a13b   a6ebd1c1ad98                         "/usr/local/bin/kube…"   8 minutes ago   Up 8 minutes              k8s_kube-proxy_kube-proxy-stljm_kube-system_44bbbc1a-00fb-4f1e-bcdd-90580f6083c2_0
bb5d2dc31f19   k8s.gcr.io/pause:3.4.1               "/pause"                 8 minutes ago   Up 8 minutes              k8s_POD_kube-proxy-stljm_kube-system_44bbbc1a-00fb-4f1e-bcdd-90580f6083c2_0

# 由于master节点还差一些配置,coredns暂时无法正常启动
# 此时主节点状态

[root@node1 ~]# kubectl get nodes
NAME    STATUS     ROLES                  AGE   VERSION
node1   NotReady   control-plane,master   43m   v1.21.2
node2   NotReady   <none>                 36m   v1.21.2
node3   NotReady   <none>                 35m   v1.21.2

# 配置flannel网络

mkdir -p /root/k8s/
cd /root/k8s
wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

#此yml中的"Network": "10.244.0.0/16" 要和 kubeadm init 中 --pod-network-cidr 一样;
#否则可能会使得Node间 Cluster IP 不通。

# 查看需要下载的镜像

cat kube-flannel.yml |grep image|uniq
#image: quay.io/coreos/flannel:v0.13.1-rc1

# 下载镜像

docker pull quay.io/coreos/flannel:v0.13.1-rc1 
#push到本地仓库
docker tag quay.io/coreos/flannel:v0.14.0 192.168.1.65:5000/quay.io/coreos/flannel:v0.14.0
docker push 192.168.1.65:5000/quay.io/coreos/flannel:v0.14.0

# 部署插件

kubectl apply -f kube-flannel.yml

#PS:卸载插件用 kubectl delete -f kube-flannel.yml !!!不要轻易用,可能删除不干净。

# 系统开始自己启动服务,稍等片刻,再查询主节点状态, 已经是Ready状态了

[root@node1 k8s]# kubectl get nodes
NAME    STATUS   ROLES                  AGE   VERSION
node1   Ready    control-plane,master   51m   v1.21.2
node2   Ready    <none>                 44m   v1.21.2
node3   Ready    <none>                 44m   v1.21.2

# 下面的结果才算正常
[root@node1 k8s]# kubectl get pod --all-namespaces
NAMESPACE     NAME                            READY   STATUS    RESTARTS   AGE
kube-system   coredns-558bd4d5db-flm5j        1/1     Running   0          52m
kube-system   coredns-558bd4d5db-rt8nd        1/1     Running   0          52m
kube-system   etcd-node1                      1/1     Running   0          52m
kube-system   kube-apiserver-node1            1/1     Running   0          52m
kube-system   kube-controller-manager-node1   1/1     Running   0          52m
kube-system   kube-flannel-ds-b87lk           1/1     Running   0          101s
kube-system   kube-flannel-ds-kpghj           1/1     Running   0          101s
kube-system   kube-flannel-ds-tmrr2           1/1     Running   0          101s
kube-system   kube-proxy-9r9zh                1/1     Running   0          52m
kube-system   kube-proxy-h88jk                1/1     Running   0          45m
kube-system   kube-proxy-stljm                1/1     Running   0          45m
kube-system   kube-scheduler-node1            1/1     Running   0          52m

# 试一试设置命令补全(Worker机器也适用)

yum install -y bash-completion
source <(kubectl completion bash) # 重启失效
echo "source <(kubectl completion bash)" >> ~/.bashrc # 重启生效
source  ~/.bashrc

可能会出现下面这种警告,附上解决办法。

# 查询集群健康状态

kubectl get cs

# scheduler            Unhealthy
# controller-manager   Unhealthy
# 这是/etc/kubernetes/manifests下的kube-controller-manager.yaml和kube-scheduler.yaml设置的默认端口是0
# - --port=0

#注释掉就可以了,之后三台机器都重启kubelet
#参考:https://llovewxm1314.blog.csdn.net/article/details/108458197

systemctl status kubelet.service
systemctl restart kubelet.service

Worker Node配置
Worker上也要安装两个基础的容器,由于我的三台机器之前使用了docker swarm 创建过集群,所以node2,node3已经在集群节点中可以看到了,如果新机器加入群集需要按此步骤

docker pull registry.aliyuncs.com/google_containers/pause:3.2
docker tag registry.aliyuncs.com/google_containers/pause:3.2 k8s.gcr.io/pause:3.2
docker rmi registry.aliyuncs.com/google_containers/pause:3.2

#worker服务器上的版本可以和master不一样
docker pull registry.aliyuncs.com/google_containers/kube-proxy:v1.19.4
docker tag registry.aliyuncs.com/google_containers/kube-proxy:v1.19.4 k8s.gcr.io/kube-proxy:v1.19.4
docker rmi registry.aliyuncs.com/google_containers/kube-proxy:v1.19.4


#我用了本地仓库
docker pull 192.168.1.65:5000/k8s.gcr.io/kube-proxy:v1.21.2
docker tag 192.168.1.65:5000/k8s.gcr.io/kube-proxy:v1.21.2  k8s.gcr.io/kube-proxy:v1.21.2
docker pull 192.168.1.65:5000/k8s.gcr.io/pause:3.4.1
docker tag 192.168.1.65:5000/k8s.gcr.io/pause:3.4.1  k8s.gcr.io/pause:3.4.1

Worker节点支持K8s命令
类似Master的K8s命令也可以在Worker节点执行:
# copy admin.conf文件 到 workder 节点

scp /etc/kubernetes/admin.conf node2:/etc/kubernetes
scp /etc/kubernetes/admin.conf node3:/etc/kubernetes

# 设置环境变量

echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile
export KUBECONFIG=/etc/kubernetes/admin.conf

# 注册新节点
# 当前Worker加入集群

kubeadm join 192.168.1.65:6443 --token vvrbdu.w5hc25hp418cixw9 \
    --discovery-token-ca-cert-hash sha256:e1c3ff1b568bf21114e3be23a6d93753b820ceec386b0fff0054dd9a13e901cc

# 在Master中检查集群的状态:

kubectl cluster-info
kubectl get cs
kubectl get pod  --all-namespaces
kubectl get nodes
kubectl get service
kubectl get serviceaccounts

# 删除节点node3

依次在Master和Worker服务器上执行下面几条,然后重新走 注册流程

#Master
[root@node1 ~]# kubectl delete nodes node3
node "node3" deleted

#node3
[root@node3 ~]# docker ps -qa | xargs docker rm -f
[root@node3 ~]# rm -rf /etc/kubernetes/kubelet.conf 
[root@node3 ~]# systemctl restart docker.service kubelet.service
[root@node3 ~]# rm -rf /etc/kubernetes/pki/ca.crt

#重新加入集群

kubeadm join 192.168.1.65:6443 --token vvrbdu.w5hc25hp418cixw9 --discovery-token-ca-cert-hash sha256:e1c3ff1b568bf21114e3be23a6d93753b820ceec386b0fff0054dd9a13e901cc

[preflight] Running pre-flight checks
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Starting the kubelet
[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap...

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

#查看节点

[root@node3 ~]# kubectl get  nodes
NAME    STATUS   ROLES                  AGE   VERSION
node1   Ready    control-plane,master   85m   v1.21.2
node2   Ready    <none>                 78m   v1.21.2
node3   Ready    <none>                 54s   v1.21.2

# 问题汇总
如何重置Master

# 重置Master上的k8s,重新从 init 开始,这种没有清理干净一般会遇到很多问题,谨慎使用

kubeadm reset

Worker加入新的Master

已经使用过的Workder节点加入新的Master,可能会遇到无法加入报错的问题:
[kubelet-check] Initial timeout of 40s passed.
timed out waiting for the condition
error uploading crisocket

# 解决办法就是重置。重置Worker节点比较容易,一般不会出问题。

kubeadm reset
systemctl daemon-reload
systemctl restart kubelet
iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X
# will reset iptables

Master上显示worker的角色名称,通过Label标记:

kubectl label nodes node2 node-role.kubernetes.io/worker=worker
[root@node1 ~]# kubectl get nodes
NAME    STATUS   ROLES                  AGE    VERSION
node1   Ready    control-plane,master   90m    v1.21.2
node2   Ready    worker                 83m    v1.21.2
node3   Ready    <none>                 6m2s   v1.21.2

简单示例
Pod是K8s中你可以创建和部署的最小也是最简的单位。Pod中封装着应用的容器(也可以是好几个容器)、存储、独立的网络IP,管理容器如何运行的策略选项。

一个Pod中运行一个容器

下面我们在刚配置好的K8s集群中,创建一个nginx容器nginx-svc.yaml。

apiVersion: v1
kind: Pod
metadata:
  name: nginx-test
  labels:
    app: web
spec:
  containers:
  - name: front-end
    image: nginx:1.7.9
    ports:
    - containerPort: 80

运行命令

**# 创建Pod**
kubectl create -f ./nginx-svc.yaml

**# 查看Pod**
kubectl get po

**# 查看Pod详细情况**
kubectl describe po nginx-test

**# 进入到Pod(容器)内部**
kubectl exec -it nginx-test /bin/bash
#新版本用这个,加两个--[空格]
kubectl exec -it nginx-test -- /bin/bash

一个Pod中运行多个容器

配置文件nginx-redis-svc.yaml

apiVersion: v1
kind: Pod
metadata:
  name: rss-site
  labels:
    app: rss-web
spec:
  containers:
    - name: front-nginx
      image: nginx:1.7.9
      ports:
        - containerPort: 80
    - name: rss-reader
      image: redis
      ports:
        - containerPort: 88

运行命令

kubectl create -f ./nginx-redis-svc.yaml
kubectl get po
kubectl describe po rss-site 
kubectl exec -it rss-site -c front-nginx /bin/bash 
kubectl exec -it rss-site -c rss-reader /bin/bash
#新版本用这个
kubectl exec -it rss-site -c front-nginx -- /bin/bash 
kubectl exec -it rss-site -c rss-reader -- /bin/bash

这里重点说一下,一个Pod中有两个容器,他们公用同一个根pause:
image-20210129184508415

安装web端面板

kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.3.1/aio/deploy/recommended.yaml

开发测试环境生成ssl证书,以在web端能登录

openssl genrsa -out server.key 1024
openssl req -new -key server.key -out server.csr
openssl x509 -req -in server.csr -out server.crt -signkey server.key -days 3650

创建登录账户TOKEN
管理账户

vim dashboard-adminuser.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: admin-user
  namespace: kubernetes-dashboard
绑定集群访问角色
vim dashboard-clusterRoleBinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: admin-user
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
- kind: ServiceAccount
  name: admin-user
  namespace: kubernetes-dashboard
kubectl apply -f dashboard-adminuser.yaml
kubectl apply -f dashboard-clusterRoleBinding.yaml

查看登录账户TOKEN

kubectl -n kubernetes-dashboard get secret $(kubectl -n kubernetes-dashboard get sa/admin-user -o jsonpath="{.secrets[0].name}") -ogo-template="{{.data.token | base64decode}}"

创建代理访问面板

kubectl proxy --accept-hosts=^.*$ --accept-paths=^/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/

Starting to serve on 127.0.0.1:8001
面板访问地址:
http://127.0.0.1:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/

默认端口是8001,这个地址内部主机访问,可以使用nginx反向代理到这个地址,并添加前面我们生成的证书使用https://192.168.1.65:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
不使用https访问,则不能通过token登录面板

参考:https://www.cnblogs.com/wenyang321/p/14050893.html

一 删除非管理员账号,配置业务账号,合理分配业务账号权限,一般除了增删改查建表删表改表,其它权限一律不给
二 修改默认的mysql管理员帐号root为其它名字
三 使用独立系统用户运行msyql程序,不要使用ROOT用户来运行
四 禁止未授权的远程连接数据库,远程账号禁止使用username@'%'
五 系统目录权限,mysql安装根目录属root用户,存放数据的data目录属mysql用户,必须保证该目录不能让未经授权的用户访问后把数据库打包拷贝走了
六 禁止MySQL对本地文件存取

mysql中,提供对本地文件的读取,使用的是load data local infile命令,默认在5.0版本中,该选项是默认打开的,该操作令会利用MySQL把本地文件读到数据库中,然后用户就可以非法获取敏感信息了,假如你不需要读取本地文件,请务必关闭。

测试:首先在测试数据库下建立sqlfile.txt文件,用逗号隔开各个字段

# vi sqlfile.txt
1,sszng,111
2,sman,222
#mysql> load data local infile 'sqlfile.txt' into table users fields terminated by ','; //读入数据
#mysql> select * from users;
+--------+------------+----------+
| userid  | username   | password |
+--------+------------+----------+
|      1 | sszng    | 111   |
|      2 | sman    | 222  |
+--------+------------+----------+

成功的将本地数据插入数据中,此时应该禁止MySQL中用“LOAD DATA LOCAL INFILE”命令。网络上流传的一些攻击方法中就有用它LOAD DATA LOCAL INFILE的,同时它也是很多新发现的SQL Injection攻击利用的手段!黑客还能通过使用LOAD DATALOCAL INFILE装载“/etc/passwd”进一个数据库表,然后能用SELECT显示它,这个操作对服务器的安全来说,是致命的。可以在my.cnf中添加local-infile=0,或者加参数local-infile=0启动mysql。

七 Mysqld安全相关启动选项

下列mysqld选项影响安全:

   --allow-suspicious-udfs
该选项控制是否可以载入主函数只有xxx符的用户定义函数。默认情况下,该选项被关闭,并且只能载入至少有辅助符的UDF。这样可以防止从未包含合法UDF的共享对象文件载入函数。
    --local-infile[={0|1}]
如果用–local-infile=0启动服务器,则客户端不能使用LOCAL in LOAD DATA语句。
    --old-passwords
强制服务器为新密码生成短(pre-4.1)密码哈希。当服务器必须支持旧版本客户端程序时,为了保证兼容性这很有用。
     (OBSOLETE) --safe-show-database
在以前版本的MySQL中,该选项使SHOW DATABASES语句只显示用户具有部分权限的数据库名。在MySQL 5.1中,该选项不再作为现在的 默认行为使用,有一个SHOW DATABASES权限可以用来控制每个账户对数据库名的访问。
    --safe-user-create
如果启用,用户不能用GRANT语句创建新用户,除非用户有mysql.user表的INSERT权限。如果你想让用户具有授权权限来创建新用户,你应给用户授予下面的权限:
mysql> GRANT INSERT(user) ON mysql.user TO ‘user_name’@’host_name’;
这样确保用户不能直接更改权限列,必须使用GRANT语句给其它用户授予该权限。
    --secure-auth
不允许鉴定有旧(pre-4.1)密码的账户。
    --skip-grant-tables
这个选项导致服务器根本不使用权限系统。这给每个人以完全访问所有的数据库的权力!(通过执行mysqladmin flush-privileges或mysqladmin eload命令,或执行FLUSH PRIVILEGES语句,你能告诉一个正在运行的服务器再次开始使用授权表。)
    --skip-name-resolve
主机名不被解析。所有在授权表的Host的列值必须是IP号或localhost。
    --skip-networking
在网络上不允许TCP/IP连接。所有到mysqld的连接必须经由Unix套接字进行。
    --skip-show-database
使用该选项,只允许有SHOW DATABASES权限的用户执行SHOW DATABASES语句,该语句显示所有数据库名。不使用该选项,允许所有用户执行SHOW DATABASES,但只显示用户有SHOW DATABASES权限或部分数据库权限的数据库名。请注意全局权限指数据库的权限。

八 确保数据文件在非系统分区:操作系统上有明确的系统分区和非系统分区。如果数据文件在系统分区,会提高整个系统因为磁盘空间用尽发生拒绝服务的几率。

1)进入数据库执行下列语句

show variables where variable_name = 'datadir'

如果发现结果中存在/ /var /usr 说明数据文件在系统分区建议换区

九 禁止 mysql 链接历史记录:
mysql 会把客户端登陆的交互执行记录保存在.mysql_history 文件中,该记录有可能会暴露登陆过程中的敏感信息,建议删除,检查.mysql_history 文件是否存在(默认在home 下)执行命令 find /home -name ".mysql_history"如果有返回行说明存在建议删除

十 禁止 MYSQL_PWD 的使用:
MYSQL_PWD 是一种用于明文形式存储 mysql 密码的环境变量,检查 MYSQL_PWD 环境变量是否存在于某个进程中执行命令

grep MYSQL_PWD /proc/*/environ

如果有返回行说明那个进程使用了 MYSQL_PWD 环境变量

十一 禁止 MYSQL 操作系统账号登陆:
Mysql 的操作做系统账号在安装完数据库后,不应该有其他用途,建议禁止该账号登陆操作系统,假设 mysql 数据库操作系统账号就是 Mysql 执行下列命令

getent passwd mysql | egrep "^.*[ \ /bin\ / false| \ / sbin \ / nologin]$"

如果没有返回行则说明存在安全隐患。

十二 禁止 MYSQL 使用默认端口:
如果返回是 3306,则说明需要修改端口;执行 sql 确认端口

show global variables like 'port';

二、文件系统权限安全配置

1、确保数据文件最小权限:
执行 sql 定位数据文件地址

show variables where variable_name = 'datadir';

检查路径权限是否符合最小权限原则

ls -l /.. | egrep "^d[r|w|x]{3}------\s*.\s*mysql\s*mysql\s*\d*.*mysql"

2、确保 log_bin_basename 文件最小权限:
执行 sql 定位日志文件地址 show variables like 'log_bin_basename';日志文件的权限是 660 属于 mysql

3、确保 log_error 文件最小权限:
执行 sql 定位日志文件地址

show global variables like 'log_error';

4、 确保 slow_query_log 文件最小权限:

执行 sql 定位日志文件地址

show variables like 'slow_query_log_file';

5 、确保 relay_log_basename 文件最小权限:

执行 sql 定位日志文件地址

show variables like 'relay_log_basename';

6、 确保 general_log_file 文件最小权限:

执行 sql 定位日志文件地址

show variables like 'general_log_file';

7 、确保密钥文件最小权限:

1.执行 sql 定位密钥文件地址

show variables where variable_name = 'ssl_key';

2.检查路径权限是否符合最小权限原则

ls -l | egrep "^-r--------[ \t]*.[ \t]*mysql[ \t]*mysql.*$"

如果没有返回行,则说明存在安全问题

8 、确保插件目录最小权限:

1.执行 sql 定位插件目录地址

show variables where variable_name = 'plugin_dir';

2.检查路径权限是否符合最小权限原则

ls -l /.. | egrep "^drwxr[-w]xr[-w]x[ \t]*[0-9][ \t]*mysql[ \t]*mysql.*plugin.*$"

三、Mysql 基本安全配置

1、 确保使用最新版 mysql 数据库:

执行 sql 检查数据库版本

SHOW VARIABLES WHERE Variable_name LIKE "version";

2、修改 root 用户名:
检查数据库是否有默认用户 root,执行命令:SELECT user from mysql.user where user='root; 如果有返回行则需要修改;

3、确保样例数据库删除:
样例数据库可以被所有数据库用户访问,并且可以用来消耗系统资源删除样例库可以减少攻击面;
检查数据库是否存在样例库执行 sql命令

SHOW DATABASES LIKE 'test';

4、禁用 local_infile:
以阻止黑客利用 sql 注入来读取数据库文件,检查参数状态执行命令:

SHOW VARIABLES WHERE Variable_name = 'local_infile';

如果返回值不是 off,则存在安全问题

5、确保 skip-symbolic-links 开启:
开启 skip-symbolic-links 可以禁止数据库用户删除或重名数据文件目录之外的文件,检查参数状态执行命令:

SHOW variables LIKE 'have_symlink';

6、确保插件 daemon_memcached 被禁用:

任何人可以利用 daemon_memcached 来访问或修改一部分数据,给数据库造成信息泄漏的隐患。

检查参数状态执行命令:

SELECT * FROM information_schema.plugins WHERE PLUGIN_NAME='daemon_memcached';

如果有返回行数说明有插件,需要删除

7、确保 secure_file_priv 不是空:

secure_file_priv 限制客户端可以读取数据文件的路径,secure_file_priv设置合理的值可以有效降低 sql 注入后黑客读取数据库数据的可能性。

检查参数状态执行如下命令:

SHOW GLOBAL VARIABLES WHERE Variable_name ='secure_file_priv' AND Value<>'';

如果有返回内容说明安全,否则需要修复;

8、确保 sql_mode 是 STRICT_ALL_TABLES 模式:

sql_mode 模式有三种,STRICT_TRANS_TABLES 是其中一种模式。STRICT_TRANS_TABLES 模式会检查所有更新的数据
检查参数状态执行命令:

SHOW VARIABLES LIKE 'sql_mode';

如果有返回的是 STRICT_TRANS_TABLES 说明安全,否则需要修复;

9、确保 disconnect_on_expired_password 参数是 ON:

disconnect_on_expired_password 是用来控制客户端用失效密码来访问数据库的,关闭这个参数会给数据库带来安全风险。
检查参数状态执行命令:

SHOW GLOBAL VARIABLES like 'disconnect_on_expired_password';

如果有返回的是 ON 说明安全,否则需要修复

四、Mysql 权限安全配置

1 、确保只有管理员账号有所有数据库的访问权限:

执行命令:

SELECT user, host FROM mysql.user WHERE (Select_priv = 'Y') OR (Insert_priv = 'Y') OR (Update_priv = 'Y') OR (Delete_priv = 'Y') OR (Create_priv = 'Y') OR (Drop_priv = 'Y');

如果返回的都是管理员账号说明安全,否则需要对用户清除权限;

2、非管理员账号 file_priv 不应该设置成 Y

File_priv 权限允许 mysql 用户对磁盘进行读写操作,执行命令:

select user, host from mysql.user where File_priv = 'Y'; 如果返回的都是管理员账号,否则需要对用户清除权限;

3、非管理员账号 process_priv 不应该设置成 Y

process_priv 权限允许委托账号查看当前正在执行的 sql 语句,使用超越

当前用户权限的权利,可以被攻击者所利用。执行命令:

select user, host from mysql.user where Process_priv = 'Y'; 如果返回的都是管理员账号则是安全的,否则需要对用户清除权限;

(同上)非管理员账号 super_priv 不应该设置成 Y,非管理员账号 shutdown_priv 不应该设置成 Y,

非管理员账号 create_user_priv 不应该设置成 Y,非管理员账号 grant_priv 不应该设置成 Y,

非管理员账号 reload_priv 不应该设置成 Y,非管理员账号 repl_slave_priv 不应该设置成 Y;

4、确保 DML/DDL 权限只在特定用户手上:

执行sql命令:

SELECT User,Host,Db FROM mysql.db WHERE Select_priv='Y' OR Insert_priv='Y' OR Update_priv='Y' OR Delete_priv='Y' OR Create_priv='Y' OR Drop_priv='Y' OR Alter_priv='Y';

如果返回的都是管理员账号,否则需要对用户清除权限

五、审计和日志安全配置

1、 确保 log_error 日志启动:

启用错误日志有可能会增加检测到针对 mysql 的恶意攻击行为机会,执行命令:

SHOW variables LIKE 'log_error';

如果返回是空否,则存在安全问题需要修复

2、 确保日志文件在非系统分区:

操作系统上有明确的系统分区和非系统分区,如果日志文件在系统分区,会提高整个系统因为磁盘空间用尽发生拒绝服务的几率;进入数据库执行命令:

SELECT @@global.log_bin_basename;

3、确保 log_warnings 被设置成 2:

log_warnings 适用于决定日志中记录的内容的,默认是 1 随着级别的调整会记录更多信息,调整到 2 有助于通过日志追查安全问题;执行命令:

SHOW GLOBAL VARIABLES LIKE 'log_warnings';

六、身份认证安全配置

1、确保 sql_mode 中含有 NO_AUTO_CREATE_USER:

NO_AUTO_CREATE_USER 是 sql_mode 的一个选项,可以阻止 grant 语句在特定情况下自动创建用户;执行命令:

SELECT @@session.sql_mode;

2、确保没有用户使用空密码

如果密码被设置成空密码,入侵者只要知道密码和主机允许列表,就可以绕

过身份验证随意登录数据库;执行命令:

SELECT User,host FROM mysql.user WHERE authentication_string=''; 

没有行数返回说明安全,否则需要配置;

3、确保 default_password_lifetimes 少于或等于 90 天

密码需要定期更换,才有意义,也才能更有效的防止黑客破解;执行命令:

SHOW VARIABLES LIKE 'default_password_lifetime';

看返回值和 90 的关系如果大于 90 就需要修复

4、 确保用户不允许所有 ip 访问

某一数据库用户支持所有 ip 访问,一旦账号密码泄露,数据库就变得很不安全,执行命令:

SELECT user, host FROM mysql.user WHERE host = '%';

结果集为空说明不存在问题,否则需要修复

5、确保无匿名帐户存在

匿名用户是空的,也没有密码,安全性很差,任意人员都可以利用匿名用户

访问数据库,执行命令:

SELECT user,host FROM mysql.user WHERE user = '';

结果集为空说明不存在问题,否则需要修复;

七、网络安全配置

1、确保 have_ssl 设置成 yes:

所有网络请求必须走 SSL/TLS 访问数据库,执行命令:

SHOW variables WHERE variable_name = 'have_ssl';

返回 yes 不存在问题,否则需要修复;

2 、确保 ssl_type 是 'ANY', 'X509', or 'SPECIFIED':

所有网络请求必须走 SSL/TLS 访问数据库。SSL 提供多种算法,其中一些算法安全性并不高不能帮助用户杜绝网络劫持和网络拦截。建议设置 ssl_type 为高安全类型的加密算法。但这其中有一个隐患,如果客户端使用较低加密算法,会由于算法无法匹配导致链接失败,执行命令:

SELECT user, host, ssl_type FROM mysql.user WHERE NOT HOST IN ('::1', '127.0.0.1', 'localhost');

确保每个用户返回的 ssl_type 等于 ANY, X509, or SPECIFIED;

八、复制数据传输中的安全配置

1 、确保 MASTER_SSL_VERIFY_SERVER_CERT 设置成 yes 或 1:

2、确保 master_info_repository 设置成 table:

master_info_repository 设置成 table.客户端使用的密码存储在表中,相较于文件系

统表中更为安全执行命令:

SHOW GLOBAL VARIABLES LIKE 'master_info_repository';

master_info_repository 返回是 table,否则需要修复,修复建议:打开配置文件

set the master_info_repository value to TABLE;

扩展资料:

secure-file-priv特性
secure-file-priv参数是用来限制LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE()传到哪个指定目录的。

show variables like '%secure%';

如果secure_file_priv如果非空,则只能在对应的目录下读文件,如果是空即可在其他目录写。Linux下默认/tmp目录可写。

当secure_file_priv的值为null ,表示限制mysql 不允许导入|导出
当secure_file_priv的值为/tmp/ ,表示限制mysql 的导入|导出只能发生在/tmp/目录下
当secure_file_priv的值没有具体值时,表示不对mysql 的导入|导出做限制
可以在mysql-ini文件中设置其属性
攻击者可以,编写一句phpinfo文件,例子是windows服务器,这里必须注意要双反斜线,否则会转义

select "<?php phpinfo();?>" INTO OUTFILE  "d:\\phpstudy\\www\\7.php"

内网穿透 100IP免费
https://www.zerotier.com/

FRP实现(需要绑定映射端口)
https://github.com/fatedier/frp

第一种方案是云服务器+Frp,但是需要单独做端口转发;第二种方案是云服务器+ZeroTier One组件局域网(100节点免费),但是有个问题是ZeroTier One本身的服务器都在国外访问速度很慢。可以通过搭建国内Moon服务加速解决连接慢的问题。

两种方案都需要有固定外网IP的服务器

下面是配置Moon的步骤(Linux):

1、安装 moon,zerotier官方提供了比较方便的安装方式,一条命令即可完成:

curl -s https://install.zerotier.com/ | sudo bash

2.生成moon配置文件

cd /var/lib/zerotier-one
sudo zerotier-idtool initmoon identity.public > moon.json
  1. 修改配置文件moon.json,主要是添加公网IP,修改内容如下, 9993是默认端口

    vim moon.json #找到对应行修改内容
    "stableEndpoints": [ "23.23.23.23/9993" ]

    注:23.23.23.23为公网ip, 一定要配置正确,Zerotier依靠此配置去连接moon.后面的端口若没有改变则默认都是9993端口, 且是UDP协议的, 此处在防火墙上需要开放UDP,否则是连接不上Moon

4.生成moon文件

sudo zerotier-idtool genmoon moon.json

执行该命令后,会在在/var/lib/zerotier-one目录下生成一个类似000000xxxxx.moon的文件

5.使moon配置文件生效:

在/var/lib/zerotier-one目录下,新建一个 moons.d 文件夹,并将刚生成的moon配置文件放到该文件夹下

mv 00000018fasd2319.moon moons.d/
  1. 重新启动moon服务器,由于使用命令安装时会自动注册为服务,所以可以依靠以下命令完成启动或重启

    service zerotier-one restart #服务重启命令

    经过以上配置,服务器上的moon即配置并应用完闭.

  2. 客户端连接并使用服务器上的Moon

直接在zerotier目录下,创建moons.d文件夹,并且将生成的000000xxxxxxxx.moon文件拷入,并重启服务即可

环境 centos8,编译方式安装的nginx/1.20.1, php 是dnf安装的php/7.2.24

nginx 执行用户、php 执行用户、文件权限都检查了,确定没有问题

nginx 的php配置也确定没有问题,但就是访问php页面出现 File not found

查看nginx报错内容,看到如下错误:"Primary script unknown"

2021/07/07 20:40:02 [error] 8853#0: *164 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 192.168.1.95, server: localhost, request: "GET /index.php HTTP/1.1", upstream: "fastcgi://unix:/run/php-fpm/www.sock:", host: "192.168.1.69"

最终解决的方法:

#/www/wwwroot/phpwebdir/是我的网站根目录
chcon -R -t httpd_sys_content_t /www/wwwroot/phpwebdir/
chcon -R -t httpd_sys_content_t /www/server/nginx/sbin/nginx 
/www/server/nginx/sbin/nginx -s reload

原因是selinux 在作祟,如上命令是配置 网站目录和nginx执行文件的 selinux 上下文
具体selinux这个安全机制至今还没有搞明白咋玩
用以下命令可以查看文件或目录的上下文

ll -dZ /www/wwwroot/phpwebdir/

修改之前是

drwxrw-rw-. 7 www www unconfined_u:object_r:admin_home_t:s0 4096 Jul  7 20:28 /www/wwwroot/phpwebdir/

修改之后是

drwxrw-rw-. 7 www www unconfined_u:object_r:httpd_sys_content_t:s0 4096 Jul  7 20:28 /www/wwwroot/phpwebdir/

或者干脆关闭selinux(需要重启服务器)
/etc/selinux/config :

SELINUX=disabled