Kubernetes挂载存储

示例说明

为演示在Kubernetes挂载存储以下面为例:

  • fortune进程 利用fortune游戏每10秒钟更新一次html文档;并将更新过程钟写入日志。

  • web-server进程 使用nginx作为web服务器向外提供服务,客户展示fortune生成的html文件。

  • log-server进程 使用nginx作为服务器向外提供服务,可以查询fortune日志。

分别将上述进程部署到不同的容器中,容器间通过挂载emptyDir卷共享信息。

测试代码

  • fortune程序
1
2
3
4
5
6
7
8
9
10
11
12
#! /bin/bash
trap "exit" SIGINT
mkdir /var/htdocs
mkdir /var/fortune

while :
do
echo $(date) writing fortune to /var/htdocs/index.html >> /var/log/fortune/$(date +%Y-%m-%d).log
/usr/games/fortune > /var/htdocs/index.html

sleep 10
done

每10秒钟生成一次html文件,并记录生成日志

  • fortune的dockerfile
1
2
3
4
5
FROM ubuntu:latest
RUN apt update ; apt install -y fortune
ADD fortuneloop.sh /bin/fortuneloop.sh

ENTRYPOINT /bin/fortuneloop.sh
  • 将三个示例容器部署到一个POD中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
apiVersion: v1
kind: Pod
metadata:
name: fortune
labels:
app: fortune
spec:
containers:
- name: html-gen
image: 172.17.0.1:5000/fortune
volumeMounts:
- name: html
mountPath: /var/htdocs
- name: log
mountPath: /var/log/fortune
- name: web-server
image: 172.17.0.1:500/nginx:alpine
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
readOnly: true
ports:
- containerPort: 80
protocol: TCP
- name: log-server
image: 172.17.0.1:5000/nginx:log
volumeMounts:
- name: log
mountPath: /usr/share/nginx/log
readOnly: true
ports:
- containerPort: 8080
protocol: TCP
volumes:
- name: html
emptyDir: {}
- name: log
emptyDir: {}

nginx:log源于nginx:alpine镜像,只是将nginx默认80端口修改成8080端口,将默认的html root目录修改成/usr/share/nginx/log目录,具体修改方法下次在详细讲。

  • 建立一个NodePort类型的Service对外提供web服务
1
2
3
4
5
6
7
8
9
10
11
12
13
kind: Service
apiVersion: v1
metadata:
name: fortune-web-nodeport
spec:
selector:
app: fortune
type: NodePort
ports:
- port: 8088
targetPort: 80
nodePort: 30157

注意selector实际是按照POD中容器标签进行选择的,因此该信息必须和POD中设置的标签保持一致; targetPort和容器端口一致,nginx:alpine默认端口是80端口

  • 建立一个NodePort类型的Service对外提供log服务
1
2
3
4
5
6
7
8
9
10
11
12
kind: Service
apiVersion: v1
metadata:
name: fortune-log-nodeport
spec:
selector:
app: fortune
type: NodePort
ports:
- port: 8090
targetPort: 8080
nodePort: 30159

注意selector实际是按照POD中容器标签进行选择的,因此该信息必须和POD中设置的标签保持一致; targetPort和容器端口一致,nginx:log默认端口是8080端口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: fortune-ingress
spec:
rules:
- host: fortune-web.local.com
http:
paths:
- path: /
backend:
serviceName: fortune-web-nodeport
servicePort: 8088
- host: fortune-log.local.com
http:
paths:
- path: /
backend:
serviceName: fortune-log-nodeport
servicePort: 8090

通过Ingress对外提供访问策略,分别根据不同的域名选择到不同的服务中。 新版本的Kubernetes提供了新的网络策略接口,在后续文章中详细测试。

  • 配置域名和IP地址

在minikube中创建ingress后可以通过:kubectl get ingress 查询ingress信息,该信息中包含了域名和IP地址的对应信息,在/etc/hosts中配置该信息即可在本机通过域名访问服务。

测试结果

  • 查询资源信息

  • 修改hosts文件

  • 访问web和log服务

Kubernetes将服务暴露给外部方式

kubernets集群内部的服务可以直接环境变量、内部DNS等方式被发现,并在集群内部提供服务。如何将Kubernetes的服务暴露给外部客户端呢? Kubernetes提供以下集中方式将服务暴露给开外部客户端:

通过NodePort暴露服务

顾名思义,将服务类型设置成NodePort方式,Kubernetes会在集群每个节点上打开一个端口,将该端口的流量转发到服务的POD。

通过负载均衡器暴露

负载均衡方式实际是NodePort方式的增强,将服务类型设置成LoadBalancer方式实际是通过云基础架构提供的负载均衡器,将流量转发到集群内部的NodePort上。

通过Ingress暴露

Ingress是Kubernetes一种资源,通过类似LoadBalancer类似的能力,区别在于每个LoadBalancer都需要一个独立的公网IP,而Ingress只需要一个公网IP即可根据规则将流量转发到对应的服务。

Kubernetes发现服务

Kubernetes发现服务

由于Kubernetes的POD的生命是短暂的,可以随时被创建和销毁,不能通过指定IP和端口号被客户端发现。另外,对于水平伸缩的POD,由多个POD提供服务,客户端也无需关心由那个POD提供服务,也就无需关心POD的部署位置。

通过引入服务(Service)提供稳定外部访问机制。

我们可以为服务创建多个端口。例如:一个servcie可以有80和443端口,通过80和443端口将外部访问转发到POD的8080和8443端口。

  • 服务发现
    • 通过环境变量发现服务 服务的创建早于POD,POD创建时k8s会通过环境变量发现服务;

    • 通过DNS发现服务 k8s集群提供了一个kube-dns POD,所有的POD都使用DNS(通过修改POD的/etc/resolv.conf文件实现)。

    • 通过FQPN发现服务

使用minikube部署本地镜像

启用本地镜像Hub

  • 使用如下命令启动本地镜像仓库

    sudo docker run -d -p 5000:5000 --restart=always --name registry registry

  • 查询是否启用成功

    curl -X GET 172.17.0.1:5000/v2/_catalog

    因为当前没有Push任何镜像到本地镜像仓库,查询结果是空。

Push镜像到local Hub

  • 为本地镜像打一个tag

    docker tag kubia 172.17.0.1:5000/kubia

  • 向本地镜像仓库推送镜像

    docker push 172.17.0.1:5000/kubia

  • 再次查询本地镜像仓库

    curl -X GET 172.17.0.1:5000/v2/_catalog

    返回: {"repositories":["kubia"]}

添加本地镜像到配置文件

sudo vim /etc/docker/daemon.json

加入如下信息:

1
2
3
4
5
6
7
8
{
"registry-mirrors": [
"https://hub-mirror.c.163.com",
"https://registry.docker-cn.com"
],
"insecure-registries":["172.17.0.1:5000"] //增加本地镜像地址
}

这里的配置需要注意:172.17.0.1:5000,需要和tag镜像信息保持一致; 重启docker服务是配置生效: systemctl restart docker

新建一个minikube集群

minikube start --driver=docker --insecure-registry="172.17.0.1:5000" --registry-mirror="https://hub-mirror.c.163.com"

这里的本地ip地址必须和上述配置的一致。 由于docker pull镜像默认使用的https协议,因此需要明确告诉docker服务和minikube使用http协议(insecure-registry)

从local registry运行一个docker应用

  • 运行docker应用

    kubectl run kubia --image=172.17.0.1:5000/kubia --port 3000

    系统会返回:pod/kubia created

    docker run是运行一个rs,而不是delploy一个应用,无需要指定部署文件

  • 查询POD信息

    kubectl get pods,系统会返回pod运行状态,如果有异常可以使用 kubectl describe pod kubia 查询详细信息。

    1
    2
    NAME    READY   STATUS    RESTARTS   AGE
    kubia 1/1 Running 0 16s

  • 创建服务对象 此时虽然已经集群内部部署成功,应用仍然无法从集群外部访问,此时需要通过服务开放接口

    sudo kubectl expose pod kubia --name kubia-http --type=LoadBalancer

    由于minikube不支持LoaderBalancer类型,使用默认的type类型也可以。

  • 列出服务

    kubectl get services 系统返回服务信息:

    1
    2
    3
    NAME         TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
    Kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13m
    kubia-http LoadBalancer 10.99.35.111 <pending> 3000:31902/TCP 97s
    此时查询到服务仍然未分配外部IP,minikube可以使用 minikube service kubia-http访问的服务的IP和端口。

    1
    2
    3
    4
    5
    6
    |-----------|------------|-------------|---------------------------|
    | NAMESPACE | NAME | TARGET PORT | URL |
    |-----------|------------|-------------|---------------------------|
    | default | kubia-http | 3000 | http://192.168.3.15:31902 |
    |-----------|------------|-------------|---------------------------|

    使用http://192.168.3.15:31902即可访问服务。

pod,service和rc之间的关系

镜像推送部署和应用部署流程

完成第一个docker应用程序

本文参考《Kubernetes in action》中的案例,部署一个node.js应用。在vscode中搭建node.js开发环境请自行百度。

创建应用程序

1
2
3
4
5
6
7
8
var http=require('http');

http.createServer(function(req,res){
res.writeHead(200,{'Content-Type':'text/plain'});
res.end('hello node.js');
}).listen(3000,'0.0.0.0',function(){
console.log('Server running at http://localhost:3000');
});

使用 node app.js启动应用程序,使用curl localhost:3000即可验证应用部署是否成功。

编写Dockerfile

1
2
3
FROM node:12
ADD app.js /app.js
ENTRYPOINT [ "node", "app.js" ]
> 注意: > 1. dockerfile 和app.js 在同一目录下 > 2. node版本号最好根据当期开发环境中版本保存一致,具体版本号使用node -v查询

制作镜像

在dockerfile目录下执行命令:sudo docker build -t kubia .

运行程序

sudo docker run --name kubia-container -p 3000:3000 -d kubia

验证应用

在浏览器中访问http://docker-ip:3000,浏览器显示hello node.js。docker ip可以通过ifconfig/ipconfig 命令查询

在Windwos 10 WSL2中安装Docker

最近在学习kubernets,正在阅读《Kubernetes in action》一书,为了感性化的理解书中内容决定同步在办公PC上安装书中涉及到工具和代码,今天先完成在win 10 WSL2中安装Docker。首先在win 10 WSL2中安装Docker想法是基于微软宣称的WSL2内核是真正的Linux内核,也就想当然的认为WSL2中的Ubuntu 20.04和在PC上直接安装是一致的,结果在安装过程中遇到各种小插曲。

打开硬件虚拟化支持

在BIOS中设置Intel虚拟化支持,进入到Virtualization选项中,设置Intel Virtual Technology为enable。重启以后即可在windows任务管理器-〉性能面板中查询虚拟化已开启。

升级WSL-〉WSL2

  • 升级win10到支持WLS2版本,Version 2004, Build 19041 or higher;

  • 设置WSL版本 在cmd中输入如下命令:wsl --set-default-version 2,将wsl版本设置为WSL2。

  • 安全ubuntu 20.04 在windows store中搜索ubuntu 20.04,安装ubuntu 20.04版本;安装完成后启动ubuntu 20.04系统提示

详细配置参考:https://docs.microsoft.com/en-us/windows/wsl/

安装Docker

  • 安装windows 10版本的Docker 不要直接使用系统apt的命令安装docker.io;建议下载windows 10的Docker版本,设置启动WSL即可。
  • 检查Docker安装是否成功 使用:sudo docker version查询docker版本: ### 如果显示如下信息则说明server端没有启动或者连接失败:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Client:
    Version: 19.03.12-ce
    API version: 1.40
    Go version: go1.14.4
    Git commit: 48a66213fe
    Built: Wed Jul 1 17:05:50 2020
    OS/Arch: linux/amd64
    Experimental: false
    Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.40/version": dial unix /var/run/docker.sock: connect: permission denied

  • 解决方案:
    • 使用sudo docker version查询,如果仍然显示失败;
    • 检查server是否启动

如果显示如下信息则说明启动成功:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Client:
Version: 19.03.12-ce
API version: 1.40
Go version: go1.14.4
Git commit: 48a66213fe
Built: Wed Jul 1 17:05:50 2020
OS/Arch: linux/amd64
Experimental: false

Server:
Engine:
Version: 19.03.12-ce
API version: 1.40 (minimum version 1.12)
Go version: go1.14.4
Git commit: 48a66213fe
Built: Wed Jul 1 17:05:26 2020
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: v1.3.4.m
GitCommit: d76c121f76a5fc8a462dc64594aea72fe18e1178.m
runc:
Version: 1.0.0-rc91
GitCommit: 24a3cf88a7ae5f4995f6750654c0e2ca61ef4bb2
docker-init:
Version: 0.18.0
GitCommit: fec3683

## 配置Docker

配置国内源

在Windows中配置国内源 配置Dokcer国内源时需要打开(图形化的)Docker Desktop,直接设置国内源即可;如果 在Linux系统中配置源,直接修改/etc/docker/daemon.json文件即可。详细请参考:https://docs.docker.com/registry/recipes/mirror/ 配置文件格式为JSON格式,例如:

1
2
3
{
"registry-mirrors": ["https://<my-docker-mirror-host>"]
}

常用的国内Docker如下: - docker官方中国区: https://registry.docker-cn.com - 网易: http://hub-mirror.c.163.com - ustc: http://docker.mirrors.ustc.edu.cn 可以同时配置多个源,例如:

1
2
3
4
5
6
{
"registry-mirrors": [
"https://registry.docker-cn.com",
"http://hub-mirror.c.163.com"
]
}

重启Docker服务即可生效

在Linux执行如下命令:

1
2
sudo systemctl daemon-reload
sudo systemctl restart docker

如果重启提示错误可以可根据提示的命令定位错误原因。 > Job for docker.service failed because the control process exited with error code. > > See "systemctl status docker.service" and "journalctl -xe" for details.

查询配置是否生效

sudo docker info

MX Linux 安装及配置

前几天看头条上推荐MX Linux,MX Linux号称是DistroWatch排名第一的操作系统,大部分评论时易用性比较好,此时手上恰好有一块闲置的高速U盘,就是想将MX Linux安装到U盘上尝试使用一下。

  • 准备工作

    • 杂牌4G U盘:用于制作USB启动盘
    • ScanDisk 64G USB 3.0 高速U盘:安装MX Linux到此盘;
    • 从清华镜像站https://mirrors.tuna.tsinghua.edu.cn/下载最新对MX Linux IOS文件
  • 制作启动盘

    1. 使用fdisk命令清除了4G U盘的信息,再格式化成fat32(不格式化无法自动挂载,尝试着手工挂载unbootin工具均无法识别出U盘,于是放弃了使用unbootin工具制作启动U盘);
    2. 使用dd命令制作启动U盘,dd命令使用方法自行请百度 sudo dd if=/home/mxipp/Downloads/MX-19.2_x64.iso of=/dev/sdd > 由4G U盘是USB 2.0接口的杂牌U盘,写入速度极慢,大约用10分钟才制作好启动U盘
  • 安装MX Linux

    1. 安装MX Linux前设置PC的启动选项为U盘启动
    2. 如果PC只有一个USB 3.0接口,其他USB接口为USB 2.0接口,建议将USB启动盘插到USB 2.0接口(暂时不要插入64G U盘),重启PC当PC使用U盘启动盘启动时再插入64GU盘;
    3. 系统启动后按照Live USB 系统的安装指引完成系统开始安装
      1. 需要注意的是在设置安装盘时务必选择安装到64G U盘,如果错配成PC硬盘安装时会清除硬盘上的数据
      2. 引导程序也要选择安装到64G U盘上 > 如果不清楚64G U盘挂载信息可用 sudo fdisk -l 命令查询,或者简单用盘大小判断。

    整个安装过程都是图形化操作,其他安装设置这里就不赘述了。安装完成之后系统会要求重启,重启时请拔掉4G启动盘,系统启动时就会使用安装到U盘的MX Linux启动。

  • 设置MX Linux MX Linux是基于Debian 10稳定版的发行版本,相关Debian文档进行设置,本文只说明几个关键设置。

    • 设置国内源

      • 不建议使用MX Linux图形化的repo manager修改源,repo manager修改非security源,security 源还是使用debian,更新、安装还是很慢。
      • 建议按照清华镜像站的帮助https://mirrors.tuna.tsinghua.edu.cn/help/debian/直接修改/etc/apt/sources.list
    • 更新系统 sudo apt update & upgrade

    • 安装中文输入法 推荐使用rime中文输入法:http://www.rime.im。刚开始安装时直接按照rime官网指导使用如下命令安装rime输入法: sudo apt intall ibus-rime 安装成功后遇到2个折腾了很久的问题:

      1. rime部署时报错: rime提示部署失败,错误日志记录在/tmp/目录下,实际该目录下找不到错误文件,重试多次均无法使用

      2. Ibus不能随系统启动 首先按照系统提示在.bashrc中添加环境变量,实际并不能生效;

        1
        2
        3
        export XMODIFIERS=@im=ibus
        export GTK_IM_MODULE=ibus
        export QT_IM_MODULE=ibus
        于是又在百度查到有些人建议在/etc/environment或者/etc/profile中配置均无法正常工作,折腾了2个小时也无法解决问题,于是就想到在linxu系统自动启动程序中增加ibus-daemon -dx命令,保存了一下session貌似可以正常启动ibus了,但是rime仍然无法正确工作,还是放弃了此方法。最终通过bing搜索引擎在MX Linux的官网上查到配置中文输入法的wikihttps://mxlinux.org/wiki/other/chinese-simplified-input/,同时在archwiki查询ibus相关指导https://wiki.archlinux.org/index.php/IBus,最终按照指导配置,ibus 和rime均能够正常工作。

        • 具体设置如下:
        1. 在.xprofile和.bashrc中配置
          1
          2
          3
          4
          export XMODIFIERS=@im=ibus
          export GTK_IM_MODULE=ibus
          export QT_IM_MODULE=ibus
          ibus-daemon -drx
        2. 通过MX Package Installer安装chinese-ibus,系统在安装过程中会同步安装关联的im-config工具,执行im-config -n ibus
        3. 重启PC,ibus和rime均能够正常工作

      实际在输入的安装过程中,mxlinux wiki和archwiki配置如何时ibus和rime正常工作暂未深入研究,后续有机会补充Display Manager和profile文件bashrc文件之间关系后续再详细说明

  • 几点折腾感悟

    • 技术试用、学习过程中遇到阻塞性问题,尽量在官方英文文档中查找解决问题的方法;
    • 国内百度搜索出来的东西实在不敢恭维了,使用百度搜索即使用多个英文关键字也无法搜索出强管理的英文官方网址,使用bing搜索前5条即可找到官方后者权威技术材料;
    • Arch linux指导文档详细且全面,知识点之间的关联性非常好,而且文档指导性很强;
    • MX Linux并不适合初学者用,遇到问题常常的方案很难解决;
    • Debian稳定性比较好,在10年ThinkPad T400 + 64G U盘上运行的很流畅,没有出现在Manjaro、LinuxMint上出现卡死问题(基本上是由于浏览器、编辑器等软件要求硬件加速导致的)

使用PAC文件实现浏览器自动代理

由于工作原因需要经常在不同的地方(办公室、家庭网络、机场酒店公共网络)接入到办公网络,而办公网络需要通过公司代理服务器才能访问互联网,同时公司IT部门提供了国内、海外等不同的代理服务器,这样就需要根据是否接入办公网络及访问对网址经常修改代理服务器(打开、关闭、修改不同对代理服务器等)。

目前各主流浏览器均支持Proxy Auto-Configuration (PAC) file自动设置代理,详细对配置指导可参考https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_(PAC)_file

今天主要讨论根据接入网络和访问的目标网址设置不同的代理服务器策略。

  • 需求一:根据是否接入办公网络选择不同的Proxy策略

    1. 通过家庭、酒店WIFI未(通过VPN)接入公司网络,本机localhost地址通常是192.168.x.x;
    2. 通过家庭、酒店WIFI(通过VPN)接入公司网络时,本机localhost地址通常是127.0.0.1;
    3. 通过办公室WIFI接入公司网络和场景2类似;
  • 需求二:根据目标网址选咋不同的Proxy服务器;

    1. 如果访问公司内网则不想要代理服务器;
    2. 如果是访问海外网络则选择海外Proxy服务器;
    3. 其他情况均使用国内代理服务器。
  • 通过PAC自动选择代理服务器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    function FindProxyForURL(url, host) {
    //如果没有通过VPN接入公司网络
    if (isInNet(dnsResolve('localhost'),'192.168.0.0','255.255.0.0') ||
    dnsResolve('localhost') != '127.0.0.1' // 不同对公司网络可能有差异,可以使用nslookup localhost 查询
    ) {
    return 'DIRECT';
    }

    //如果访问的时公司内网
    if (shExpMatch(host, "*.mycompany.com")) {
    return 'DIRECT';
    }
    // 如果访问对的时海外网址使用海外Proxy
    if (shExpMatch(url,'*.google.com*') || shExpMatch(url,'*.github.com*') ) {
    return 'PROXY proxy_uk.mycompany.com:8080' +
    'PROXY proxy_hk.mycompany.com:8080';

    }else { //默认使用国内proxy,如果proxy不同则不使用
    return 'PROXY proxy_cn.mycompany.com:8080;' +
    'DIRECT'
    }
    }
  • 在浏览器设置PAC文件 各家浏览器均可以使用扩展或者命令参数设置PAC文件。这里推荐使用Proxy-Switcher扩展,该扩展支持Chrome/Edge/Firefox浏览器,具体参考:https://mybrowseraddon.com/proxy-switcher.html

非暴力沟通读书笔记(二)

非暴力沟通过程中除了报答自己的感受、需要和请求外也许要关注对方,也许要想对自己一样观察、感受对方,了解对方的需求和请求

  • 体会他人对感受和需求
    • 在体会他人的感受和需要是不要基于发表自己对看法、判断和建议等。
  • 给他人反馈
    • 在倾听到他人对感受、需求和请求等需要给予他人反馈,主动表达我们的理解。如果我们理解正确可以帮助对方意识到他们他们要表达对意思;如果我们理解不到位,对方则可以继续补充。
    • 一般来说一个人讲话时如果带有明显对情绪时他一般会期待得到反馈。即使在不善于表达情感的人之间只要用心体会他人对感受都会促进两者之间关系,例如:中年儿子和年迈对父亲之间。
  • 保持关注
    • 我们需要在为他人表达创造条件,确保我们已经充分对观察、感受对方对需求和请求时再给予他人的建议,如果过早给对方建议,没有让对方体会到我们已经真正理解和体会到对方对感受了,对方往往会认为我们建议是敷衍的,或者是否能真正发挥作用。
  • 如果当我们痛苦的无法倾听,这说明我们也许要别人的关心,请大声说出你对感受、需要和请求。

非暴力沟通不是一个沟通对技巧,是发自内心的爱或者真诚的希望改善和周围人关系。

非暴力沟通读书笔记(一)

非暴力沟通中强调合理表达诉求,而不是指责、批评或者抱怨对方对行为。例如:

  • 案例一 > 我很生气,你惹我不高兴了!

    更好一些对表达是: > 你约会迟到了,我很生气。

    但是上述表达中表达了自己对感受,但是指责了对方的行为,需要将指责对方的行为修改为表达自己对诉求: > 我很生气,我希望你约会能按时到,这样我们就有时间一起吃饭,还可以看一场电影。

  • 案例二 > 如果你下次在这样做事情,你不如不做!

    需要将上述对沟通方式调整为表达自己对感受,并说出自己对需求/诉求:

    我很失望,我希望你在涮碗的同时也把餐桌擦干净,这样我就不需要做这些了。

我们的愤怒、不高兴、失望等负面情绪往往是因为我们的期望没有得到满足,在沟通过程中如果只是通过批评、吼叫等行为表达了自己的情绪,而不是通过非暴力对方式表达自己对诉求/需求。在听到不中听对话我们往往会产生以下行为: 1. 认为自己犯了错,而产生自责或这内疚的情绪 2. 指责对方,或者驳斥对方 3. 了解我们对感受和需要 4. 用心体会他人对感受和需要

因此在沟通过程中表达自身对感受和需要,倾听对方对感受和需要开始非暴力对沟通。