k8s 学习笔记

命令汇总查看

命令 描述
kubectl get svc/services 获取 创建的services信息
kubectl get nodes 查看集中nodes信息
kubectl describe node < node name> 查看某个node详细信息
kubectl scale re redis-slave --replicas=3 动态缩放pod副本数
kubectl get deployments 查看deployment信息
kubectl describe deployments 查看deployment详细信息
kubectl get endpoints 查看service 对应的pod endpoint列表
etcdctl endpoint health 查看etcd二进制安装健康状态

第一章

  • 零散知识点
1、pod之间通信时,可为每个pod创建service,别的pod通过环境变量<Service_Name>_SERVICE_HOST的值连接其他服务。--在对应的rc.ymal文件种指定环境变量eg:tomcat连接数据库
kind: ReplicationController
apiVsersion: v1
metadata:
  name: myweb
spec:
  replicas: 1
  selector:
    app: myweb
  template:
    metadata:
      labels:
        app: myweb
    spec:
      containers:
        - name: myweb
          image: kubeguide/tomcat-app:v1
          ports:
          - containerPort: 8080
          env:
          - name: MYSQL_SERVICE_HOST
            value: '10.254.31.69'
          - name: MYSQL_SERVICE_PORT
            value: '3306'
2、CPU 的资源单位为CPU (Core )的数量,是一个绝对值而非相对值,Memory 配额也是一个绝对值,它的单位是内存字节数。
一个CPU 的配额对于绝大多数容器来说是相当大的一个资源配额了,所以,在Kubernetes里,通常以千分之一的CPU 配额为最小单位,用m 来表示
3、一个计算资源进行配额限定需要设定以下两个参数。
    Requests :该资源的最小申请量,系统必须满足要求。
    Limits :该资源最大允许使用的量,不能被突破,当容器试图使用超过这个量的资源时,可能会被Kubernetes Kill 并重启。
  • kuebrnetes 基本概念和术语
    1、master (4个关键进程)
Kubernetes API Server ( kube叩iserver ) : 提供了HTTP Rest 接口的关键服务进程,是Kubernetes 里所有资源的增、删、改、查等操作的唯一入口,也是集群控制的入口进程。
Kubernetes Controller Manager ( kube-controller-manager ) : Kubernetes 里所有资源对象的自动化控制中心,可以理解为资源对象的“大总管”
Kubernetes Scheduler C !rube-scheduler ): 负责资源调度( Pod 调度〉的进程,相当于公交公司的“调度室"
etcd 服务,因为Kubernetes 里的所有资源对象的数据全部是保存在etcd 中的。

2、node(3个关键进程)

kubelet:负责Pod 对应的容器的创建、启停等任务,同时与Master 节点密切协作, 实现集群管理的基本功能。
kube-proxy : 实现Kubernetes Service 的通信与负载均衡机制的重要组件。
Docker Engine ( docker) : Docker 引擎,负责本机的容器创建和管理工作。

3、pod

每个Pod 都有一个特殊的被称为“根容器”的Pause 容器,Pause 容器对应的镜像属于Kubemetes平台的一部分,除了Pause 容器,每个Pod 还包含一个或多个紧密相关的用户业务容器。
Kubemetes 为每个Pod 都分配了唯一的E 地址,称之为Pod IP , 一个Pod 里的多个容器共享Pod E 地址。Kubernetes 要求底层网络支持集群内任意两个Pod 之间的TCP/IP 直接通信,这通常采用虚拟二层网络技术来实现,例如Flannel 、Open vSwitch 等。记住一个Pod 里的容器与另外主机上的Pod 容器能够直接通信。

4、Label

1)一个Label 是一个key=value 的键值对,其中key 与value 由用户自己指定。Label 可以附加到各种资源对象上,一个资源对象可以定义任意数量的Label 。
2)同一个Label 也可以被添加到任意数量的资源对象上去, Label 通常在资源对象定义时确定,也可以在对象创建后动态添加或者删除。
我们可以通过给指定的资源对象捆绑一个或多个不同的Label 来实现多维度的资源分组管理功能
新出现的管理对象如Deplo严nent 、ReplicaSet 、Daemon Set 和Job 则可以在Se lector 中使用
基于集合的筛选条件定义,例如:P20
selector:
matchLabels :
app: myweb
matchExpressions:
- {key: tier ,operator : In , values: [frontend)}
- {key: environment , operator : Notin , values: [dev)}
可用的条件运算符包括: In 、No tin 、Exis ts 和DoesNotExist
3)Label Selector 在Kubemetes 中的重要使用场景有以下几处。
   kube-controller 进程通过资源对象RC 上定义的Label Selector 来筛选要监控的Pod 副本的数量,从而实现Pod 副本的数量始终符合预期设定的全自动控制流程。
   kube-proxy 进程通过Service 的Label Selector 来选择对应的Pod ,自动建立起每个
   Service 到对应Pod 的请求转发路由表,从而实现Service 的智能负载均衡机制。
通过对某些Node 定义特定的Label ,并且在Pod 定义文件中使用NodeSelector 这种标
签调度策略, kube咽heduler 进程可以实现Pod “定向调度”的特性。

5、Replication Controller

1) 所以RC 的定义包括如下几个部分。
  。Pod 期待的副本数( replicas )。
  。用于筛选目标Pod 的Label Selector .
  。当Pod 的副本数量小于预期数量时,用于创建新Pod 的Pod 模板( template ) 。
2)删除RC 并不会影响通过该RC 己创建好的Pod 。为了删除所有Pod ,可以设置replicas 的值为0 ,然后更新该RC 。另外, kubectl 提供了stop 和delete 命令来一次性删除RC 和RC 控制的全部Pod 。
3)Replica Sets支持基于集合的Label selector ( Set-based selector ),而RC 只支持基于等式的Label Selector(equality-based selector )
selector:
matchLabels:
tier: frontend
matchExpressions:
- {key: tier , operator: In, values: [frontend)}
4)
。在大多数情况下,我们通过定义一个RC 实现Pod 的创建过程及副本数量的自动控制。
。RC 里包括完整的Pod 定义模板。
。RC 通过Label Selector 机制实现对Pod 副本的自动控制。
。通过改变RC 里的Pod 副本数量,可以实现Pod 的扩容或缩容功能。
。通过改变RC 里Pod 模板中的镜像版本,可以实现Pod 的滚动升级功能。

6、Deployment

DESIRED : Po d 副本数量的期望值,即Deployment 里定义的Replica
CURRENT : 当前Replica 的值, 实际上是Deployment 所创建的Replica Set 里的Replica值,这个值不断增加,直到达到DESIRED 为止, 表明整个部署过程完成。
UP-TO-DATE : 最新版本的Pod 的副本数量,用于指示在滚动升级的过程中,有多少个Pod 副本已经成功升级。
AVAILABLE : 当前集群中可用的Pod 副本数量,即集群中当前存活的Pod 数量。

7、-Horizontal Pod Autoscaling-HPA Pod 横向自动扩容

apiVersion : autoscaling/vl
kind: HorizontalPodAutoscaler
metadata :
name : php-apache
namespace: default
spec:
maxReplicas : 10
minReplicas : 1
scaleTargetRef:
kind : Deplo 泸nent
name : php-apache
targetCPUUtilizationPercentage : 90

8、StatefulSet

1)StatefulSet 里的每个Pod 都有稳定、唯一的网络标识,可以用来发现集群内的其他成员。假设StatefulSet 的名字叫kafka, ,那么第l 个Pod 叫kafka-0 ,第2 个叫kafk-1 ,以此类推。
2) StatefulSet 控制的Pod 副本的启停顺序是受控的,操作第n 个Pod 时,前n-1 个Pod 己经是运行且准备好的状态。
StatefulSet 里的Pod 采用稳定的持久化存储卷,通过PV/PVC 来实现,删除Pod 时默认不会删除与Statefu!Set 相关的存储卷(为了保证数据的安全〉。
3) StatefulSet 除了要与PV 卷捆绑使用以存储Pod 的状态数据,还要Headless Service 配合使用,即在每个Statefu!Set 的定义中要声明它属于哪Headless Service 。Headless Service 与普通Service 的关键区别在于,
它没有Cl uster IP ,如果解析Headless Service 的DNS 域名,则返回的是该Service 对应的全部Pod 的Endpoint 列表。
Statefu!Set 在Headless Service 的基础上又为StatefulSet 控制的每个Pod 实例创建了一个DNS 域名,这个域名的格式为:
$(podname).$(headless service name)
4) 比如一个3 节点的Kafka 的Statefu!Set 集群,对应的Headless Service 的名字为kafka,
StatefulSet 的名字为kafka ,则StatefulSet 里面的3 个Pod 的DNS 名称分别为kafka-0.kafka 、
kafka-1.kafka、kafka-3 .kafka ,这些DNS 名称可以直接在集群的配置文件中固定下来。

9、Service

1) Kubernetes 里的每个Service 其实就是我们经常提起的微服务架构中的一个“微服务”

2) 然每个Pod 都会被分配一个单独的E 地址,而且每个Pod 都提供了一个独立的Endpoint
( Pod IP+ContainerPort )以被客户端访问,现在多个Pod 副本组成了一个集群来提供服务,那么
客户端如何来访问它们呢? 一般的做法是部署一个负载均衡器(软件或硬件),为这组Pod 开启
一个对外的服务端口如8000 端口, 并且将这些Pod 的Endpoint 列表加入8000 端口的转发列表
中,客户端就可以通过负载均衡器的对外E 地址+服务端口来访问此服务,而客户端的请求最
后会被转发到哪个Pod ,则由负载均衡器的算法所决定。

3)在spec . ports 的定义中, taretPort 属性用来确定提供该服务的容器所暴露( EXPOSE )的端
口号,即具体业务进程在容器内的targ etPort 上提供TCP/IP 接入:而port 属性则定义了Service
的虚端口。没有指定targetPort ,则默认targetPort 与port 相同。

4)service多端口问题
  -- Kubernetes 的服务发现机制
    每个Kubemetes 中的Service 都有一个唯一的Cluster IP 及唯一的名字,名字由开发者自己定义
    是如何通过Service 的名字找到对应的Cluster IP。
     每个Service 生成一些对应的Linux 环境变量CENV ),并在每个Pod 的容器在启动时,自动注入这些环境变量
      eg: service 名字叫tomcat-service 产生的环境变量条目:
      TOMCAT SERVICE SERVICE HOST=l 69 .169. 41. 218
      TOMCAT SERVICE SERVICE PORT SERVICE PORT=8080
      TOMCAT SERVICE SERVICE PORT SHUTDOWN PORT=BOOS
      TOMCAT SERVICE SERVICE PORT=8080
      TOMCAT SERVICE PORT 8005 TCP PORT=BOOS
      TOMCAT SERVICE PORT=tcp: / /169 . 169.41.218:8080
      TOMCAT SERVICE PORT 8080 TCP ADDR=l69.169.41.218
      TOMCAT_SERVICE_PORT_8080_TCP=tcp://169.169 . 41.218:8080
      TOMCAT SERVICE PORT 8080 TCP PROTO=tcp
      TOMCAT SERVICE PORT 8080 TCP PORT=8080
      TOMCAT_SERVICE_PORT_8005一TCP=tcp:/ / 169.169.41 . 2 18:8005
      TOMCAT SERVICE PORT 8005 TCP ADDR=169 . 169.41.218
      TOMCAT SERVICE PORT 8005 TCP PROTO=tcp
    DNS系统:把服务名作为DNS域名

5)外部系统访问service的问题
  Node IP: Node 节点的IP 地址。Node IP 是Kubemetes 集群中每个节点的物理网卡的IP 地址,这是一个真实存在的物理网络。
  所有属于这个网络的服务器之间都能通过这个网络直接通信。Kubemetes 集群之外的节点访问Kubemetes 集群之内的某个节点或者TCP/IP 服务时,必须要通过Node IP 进行通信。
  Pod IP: Pod 的IP 地址。它是Docker Engine 根据dockerO 网桥的E 地址段进行分配的,通常是一个虚拟的二层网络。
  Kubemetes 里一个Pod 里的容器访问另外一个Pod 里的容器,就是通过Pod E 所在的虚拟二层网络进行通信的,而真实的TCP/IP 流量则是通过Node E 所在的物理网卡流出的。
  Cluster IP: Service 的IP地址。Cluster IP 仅仅作用于Kubemetes Service 这个对象,并由Kubemetes 管理和分配IP 地址(来源于Cluster IP地址池)。
    Cluster IP 无法被Ping
    Cluster  IP 只能结合Service Port 组成一个具体的通信端口,单独的Cluster IP 不具备TCP/ IP 通信的基础,,
    并且它们属于Kubemetes 集群这样一个封闭的空间, 集群之外的节点如果要访问这个通信端口,则需要做一些额外的工作
    在Kubemetes 集群之内, Node IP 网、Pod IP 网与Cluster IP 网之间的通信, 采用的是Kubemetes 自己设计的一种编程方式的特殊的路由规则
    NodePort 的实现方式是在Kubemetes 集群里的每个Node 上为需要外部访问的Service 开启一个对应的TCP 监听端口,外部系统只要用任意一个Node 的IP 地址+具体的NodePort 端口号即可访问此服务。
service与pod,rc关系.png

10、Volume

1) 我们先在Pod 上声明一个Volume ,然后在容器里引用该Volume 并Mount 到容器里的某个目录上

2) Volume类型
  - emptyDir:它的初始内容为空,并且无须指定宿主机上对应的目录文件,因为这是Kubernetes 自动分配的一个目录
  - hostPath: 在Pod 上挂载宿主机上的文件或目录
  - gcePersistentDisk:表示使用谷歌公有云提供的永久磁盘( Persistent Disk, PD )存放Volume 的数据    详见P39
  - awsElasticBlockStore: 使用亚马逊公有云提供的EBSVolume 存储数据
  - NFS(网络文件系统):
      volumes :
        - name: nfs
          nfs :
      #改为你的NFS 服务器地址
          server: nfs-server.localhost
          path: ”/”
  - iscsi :使用iSCSI 存储设备上的目录挂载到Pod 中
  ......

11、Persistent Volume(PV)

1)PV 可以理解成Kubemetes 集群中的某个网络存储中对应的一块存储.
  PV 只能是网络存储,不属于任何Node ,但可以在每个Node 上访问
  PV 井不是定义在Pod 上的,而是独立于Pod 之外定义。
  PV 目前支持的类型包括: gcePersistentDisk 、AWSElasticBlockStore 、AzureFile 、
AzureDisk 、FC ( Fibre Channel ) 、Flocker、NFS 、iSCSI 、RBD (Rados Block Device )、
CephFS 、Cinder、GlusterFS 、V sphere Volume 、Quobyte Volumes 、VMware Photon 、Portwonc
Volumes 、ScaleIO Volumes 和HostPath (仅供单机测试)。
2) 如果某个Pod 想申请某种类型的PY ,则首先需要定义一个PersistentVolurneClaim ( PVC )对象,然后,在Pod 的Volume 定义中引用上述PVC 即可.
  volumes:
     - name: mypd
       persistentVolumeClaim:
       claimName : myclaim
3) PV的状态
  Available :空闲状态。
  Bound :己经绑定到某个PVC 上。
  Released :对应的PVC 己经删除,但资源还没有被集群收回
  Failed: PV 自动回收失败。

12、Namespace

1)Namespace 通过将集群内部的资源对象“分配”到不同的Namespace 中,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理。
2)pod中选择namespace
apiVersion: vl
kind: Pod
metadata:
  name: busybox
  namespace: development

13、Annotation (注解)

第二章

一、单master多node安装--yum安装
二、多master高可用安装--
安装详见后续文章整理

1、kube_apiserver服务

1)启动service文件
[Unit]
Description=Kubernetes API Server
Documentation=https://github . com/GoogleCloudPlatform/kubernetes
After=etcd. service
Wants=etcd.service
[Service]
EnvironmentFile=/etc/kubernetes/apiserver
ExecStart=/usr/bin/kube - apiserver $KUBE_API_ARGS
Restart=on failure
Type=notify
LimitNOFILE=65536
[Install)
WantedBy=multi-user . target

2)配置文件参数
KUBE API ARGS="......"
--etcd- servers : 指定etcd 服务的URL
--storage-backend :指定etcd 的版本,从Kubemetes v l.6 开始,默认为etcd3,前版本无此参数
--insecure-bind-address: apiserver 绑定主机的非安全E 地址,设置0 . 0 .0 . 0 表示绑定所有ip地址。
-- insecure -port : apise凹er 绑定主机的非安全端口号,默认为8080 。
--service-cluster-ip-range: Kubemete s 集群中Service 的虚拟IP 地址段范围,以CIDR 格式表示
--service-node-pod-range: Kubernetes 集群中Service 可映射的物理机端口号范围,默认为30 000 ~ 3 2767
--admission_control: Kubernetes 集群的准入控制设置,各控制模块以插件的形式依次生效。-- --logtostderr :设置为fa lse 表示将日志写入文件, 不写入stderr 。
--log-dir :日志目录。
--v:日志级别

2、controller-manager与kube-scheduler 服务

1) 启动service文件
[ Uni服务端私钥文件t ]
Description=Kubernetes Controller Manager
Documentation=https : //gith ub.com/GoogleCloudPlatform/kubernetes
After=kube-apiserver.service
Requires=kube-apiserver.service
[Service]
EnvironmentFil e=/etc/kubernetes/scheduler
ExecStart=/usr/bin/ kube-scheduler $KUBE SCHEDULER ARGS
Restart=on- failure
LimitNOFILE=65536
[Install ]
WantedBy=multi - user.target

2)配置参数
--master:指定apiserver 的URL 地址。
--logto stderr : 设置为false 表示将日志写入文件,不写入stderr
--log-dir : 日志目录。
--v:日志级别

3、Kubernetes 集群的安全设置

1)概要
  在一个安全的内网环境中, Kubernetes 的各个组件与Master 之间可以通过apiserver的非安全端口
htttp://apiserver:8080 进行访问。但如果apiserver 需要对外提供服务,或者集群中的某些容器也需要访问api server 以获取
集群中的某些信息,则更安全的做法是启用HTTPS 安全机制。
2) CA签名的双向数字证书的生成过程如下:
    (1) 为kube -apiserver 生成一个数字证书,井用CA 证书进行签名。
    (2) 为kube-api serve r 进程配置证书相关的启动参数,包括CA 证书(用于验证客户端证书的签名真伪)、自己的经过CA 
        签名后的证书及私钥。
    (3) 为每个访问Kubernetes API Server 的客户端(如kube-controller-manager 、kube-scheduler、kubelet 、
        kube-proxy 及调用API server的客户端程序kubectl 等)进程生成自己的数字证书,也都用CA 证书进行签名,在相关程序的启动
      参数里增加CA 证书、自己的证书等相关参数。
3) 对应服务秘钥生成 
  kube-apiserver 的CA 证书--server.key,server.crt,server.csr
  kube-controller-manager 的客户端证书、私钥--cs_client.key,cs_client.crt,cs_client.csr
  kube-scheduler复用kube-controller-manager 创建的客户端证书
  kubelet的客户端证书、私钥:kubelet_client.key,kubelet client.csr,kubelet client.crt
  kube-proxy复用kubelet创建的客户端证书
4)  证书启动参数
      (1) kube-apiserver
         --client-ca-file:CA 根证书文件
         --tls-cert-file:  服务端证书文件
         --tls-private-key-file: 服务端私钥文件
         --insecure-port=0   #关闭非安全端口8080
         --secure-port=6443 #开始安全端口6443(默认端口)
      (2) kube-controller-manager
          --master=https://
          --service-account-key-file
          --root-ca-file
          --kubeconfig     #配置了kube-controller-manager客户端证书等相关参数
                user:
                  client-certificate : /var/run/kubernetes/cs client.crt
                  client-key: /var/run/kubernetes/cs_client.key
                cluster:
                  certificate-authority: /var/run/kubernetes/ca.crt
     (3)kube-scheduler 启动参数
          --master=https://192.168.18.3:6443
          --kubeconfig=/etc/kubernetes/kubeconfig
      (4) kubelet
          --api-servers=https : //192.168.18.3:6443
          --kubeconfig=/etc/kubelet/kubeconfig
      (5) kube-proxy
          --master=https : //192 . 168.18.3:6443
          --kubeconfig=/etc/kubernetes/kubeconfig     #kubelet与kube-proxy公用一个kubeconfig
apiVersion : vl
kind : Config
users:
- name: kubelet
  user :
    client-certificate: /etc/kubernetes/ssl_keys/kubelet_client.crt
    client-key: /etc/kubernetes/ssl_keys/kubelet_client.key
clusters :
- name : local
  cluster :
   certificate-authority : /etc/kubernetes/ssl_keys/ca.crt
contexts :
- context:
    cluster : local
    user: kubelet
  name: my-context
current-context : my - context
4) 基于TOKEN 认证的配直过程

4、Kubernetes 核心服务配置详解 p83
在命令的配置文件中添加,修改,删除参数

  • 公共配置参数
    公共配置参数适用于所有服务(kube-apiserver、kube-controller-manager、kube-scheduler 、kubelet 、kube-proxy)
参数名和取值示例 说明
kubectl get svc/services 获取 创建的services信息

5、kubectl用法概述 kubectl [command] [TYPE] [NAME) [flags]
【TYPE】

资源对象名称 说明
cluster (cs) 集群etcd scheduler ,controller-manager 状态信息
deployments(deploy) deployment 资源信息
endpoints (ep)
events (ev)
namespaces(ns)
nodes(no)
pods(po)
pvc
pv
relicasets(rs)
replicationcontrollers(rc)
services(svc)
kubeetl get pod/podl re/rel

p105
【COMMAND】

参数名和取值示例 说明 用法
annotate 添加或更新资源对象的a nnotation信息
api-versions 列出当前系统支持的API 版本列表 kubectl api-versions [flags]
apply 从配置文件或stdin 中对资源对象进行配置更新 kubectl apply -f FILENAME [flags]
attach 附着到一个正在运行的容器上 kubectl attach POD -c CONTANER[flags]
autoscale 对Deploment,Replicatset,ReplicationController进行水平自动化扩容和缩容的设置 kubectl autoscale (-fFILENAME I TYPE NAME I TYPE/NAME)[--min= MAXPODS] --max=MAXPODS [--cpu-percent=CPU] [flags]
cluster-mfo kubectl cluster-info [flags] 显示集群M aster 和内组服务的信息
con fig kubectl config SUBCOMMAND [flags] 修改kubeconfig 文件
convert 转换配置文件为不同的API版本 kubectl convert - f FILENAME [flags]
create 从配置文件或stdin 中创建资源对象 kubectl create - fFILENAME [flags]
delete 根据配置文件、stdin、资源名称或label selector删除资源对象 kubectl delete (-fFILENAME I TYPE [NAME I NAME I -1 label --all]) [flags]
describe 描述一个或多个资源对象的详细信息
drain 首先将Node 设置为unschedulable,然后删除该Node 上二运行的所有Pod,但不会删除不由api server 管理的Pod
edit 编辑资源对象的属性,在线更新
explain 对资源对象属性的详细说明
expose 将已经存在的一个RC,Service,Deployment或Pod暴露为一个新的Service
get 显示一个或多个资源对象的概要信息
label 设置或更新资源对象的labels
logs
replace 从配置文件或stdin 替换资源对象
rollout 对Deployment 进行管理,可用操作包括: history、pause、resume、undo 、status
run 基于一个kubernetes集群上启动一个Deployment
scale 扩容、缩容一个Deployment、ReplicaSet、RC或Job中Podde 数量
set 设置资源对象的某个特定信息,目前仅支持修改容器的镜像
uncordon 将Node设置为schedulable
version

【flags】

参数和取值 说明
--alsologtostden=false 设置为true 表示将日志输出到文件的同时输出到stderr
--as=” 设置本次操作的用户名
--certificate-authority=” 用于CA 授权的cert 文件路径
--client-certificate 用于TLS 的客户端证书文件路径
--cluster= " 设置要使用的kubeconfig 中的cluster 名
--chent-key=” 用于TLS 的客户端key 文件路径
--contex t=” 设置要使用的kubeconfig 中的context 名
--insecure-skip-tls-verify=false 设置为甘ue 表示跳过TLS 安全验证模式,将使得H1寸PS 连接不安全
--kubeconfig kubeconfig 配直文件路径,在配置文件中包括Master 地址信息及必要的认证信息
--log-backtrace-at=:0 记录日志每到“file:行号”时打印一次stack trace
--log-dir=” 日志文件路径
--log-flush-frequency=5s 设置flush 日志文件的时间间隔
--logtostderr=true 设置为true 表示将日志输出到stderr ,不输出到日志文件
--match-server-version=false 设置为true 表示客户端版本号需要与服务端一致
--namespace= or -n 设置本次操作所在的namespace
--password=” 设置apiserver 的basic authentication 的密码
-s, 一server=” 设置apiserver 的URL 地址, 默认值为localhost: 8080
--stdeπ由reshold =2 在该threshold 级别之上的日志将输出到stdeπ
--token=” 设置访问apiserver 的安全token
--user=" 指定kubeconfig 用户名
--username=” 设置apiserver 的basic authentication 的用户名
--v=0 glog 日志级别

【输出格式】

输出格式 说明
-o=custom-columns=<spec> 根据自定义列名进行输出,以逗号分隔
-o=custom-columns-file=<filename> 从文件中获取自定义列名进行输出
-o=json 以JSON 格式显示结果
-o jsonpath=<template> 输出jsonpath 表达式定义的字段信息
-o jsonpath-file=<filename> 输出jsonpath 表达式定义的字段信息,来源于文件
-o name 仅输出资源对象的名称
-o wide 输出额外信息。对于Pod ,将输出Pod 所在的Node 名
-o yaml 以yaml格式显示结果

2、Pod深入掌握

Pod 定义详解

apiVersion : vl
kind: Pod
metadata :
  name : string
  namespace: string
  labels:
    - name: string
  annotations:
    - name: string
spec:
  containers:
  - name: <container-name>
    image: image-name
    iamgePullPolicy: Always|Nerver|IfNotPersent
    command: shell-command-when-container-up
    args: string
    workingDir: string
    volumeMounts:
    - name: <the container paths name mount to outside >
      mountPath: <container path>
      readOnly: boolean
    ports:
    - name: <container servicer port name>
      containerPort: int  <container is linstening port>
      hostPort: int <corresponding to host port >
      protocol: string
    env:
    - name: string
      value: string
    resources:
      limits:
        cpu: string
        memory: string
      requests:
        cpu: string
        memory: string
    livenessProbe:
      exec:
        command: string
      httpGet:
        path: string
        port: number
        host: string
        shceme: string
        httpHeaders:
        - name: string
          value: string
      tcpSocket:
        port: number
      initialDelaySeconds: 0
      timeoutSeconds: 0
      periodSeconds:0
      successThreshold: 0
      failureThreshold: 0
    securityContext:
      privileged: false
  restartPolicy: Always | Never | OnFailure
  nodeSelector: object
  imagePullsecrets:
  - name: string
  hostNetwork: false
  volumes:
  - name: string
    emptyDir: {}
    hostPath:
      path: string
    secret:
      secretName: string
      items:
      - key: string
        path: string
      configMap:
        name: string
        items:
        - key: string
          path: string
属性名称 取值类型 是否必选 取值说明
version string v1 ..查看支持的api版本<br />kubectl api-versions
kind string yes pod
metadata Object yes 元数据
metadta.name string yes pod的名称
metadata.namespace string yes pod所属的命名空间
metadata.labels[] list 自定义标签列表
metadata.annotation[] list 自定义注释列表
spec Object yes pod中容器的详细定义
spec.containers[] list yes pod中容器的列表
spec.containers[].name string yes 容器的名称
spec.containers[].image string yes 容器镜像的名称
spec.containers[].<br />imagePullPolicy string 获取镜像的策略,可选值包括: A lways 、Never、
I fNotPresent ,默认值为A lways .
Always : 表示每次都尝试重新下我镜像.
I fNotPresent : 表示如果本地有该镜像,则使用本
地的镜像,本地不存在时下载镜像.
Never: 表示仅使用本地镜像
spec.containers[].command[] list 容器的启动命令列表,如果不指定,则使用镜像打包时使用的启动命令
spec.containers[].args[] list 容器启动命令参数列表
spec.containers[].workingDir string 容器的工作目录
spec.containers[].volumeMounts[] list 挂载到勇气内部的存储卷配置
spec.containers[].<br />volumeMounts[].name list 引用Pod定义的共享存储卷命令,需要使用spec.volumes[]部分定义的共享存储卷名称
spec.containers[].<br />volumeMounts[].mountPath string 存储卷在容器内Mount的绝对路径
spec.containers[].<br />volumeMounts[].readOnly boolean 是否为只读模式,默认为读写模式
spec.containers[].ports[] list 容器需要暴露的端口号列表
spec.containers[].ports[].name string 端口的名称
spec.containers[].containerPort int 容器需要鉴定的端口号
spec.containers[].hostPort int 容器所在主机需要监听的端口号,默认与containerPort相同,设置了此端口,同一台宿主机将无法启动该容器的第二份副本
spec.containers[].protocol string 端口协议TCP,UDP
spec.containers[].env[] list 容器运行前需设置的环境变量列表
spec.containers[].env[].name string 环境变量的名称
spec.containers[].env[].value string 环境变量的值
spec.containers[].resources Object 资源限制和资源请求的设置
spec.containers[].resources
.limits
object 资源限制设置
spec.containers[].reources
.limits.cpu
string cpu限制,core
spec.containers[].reources
.limits.memory
string 内存限制MiB/GiB
spec.containers[].<br />reources.requests object 资源限制设置
spec.containers[].reources.
requests.cpu
string cpu请求,容器启动的初始化可用数量,core
spec.containers[].resources.<br />requests.memory string 内存请求,容器启动的初始可用数量
spec.volumes[] list 在该pod上定义的共享存储列表
spec.volumes[].name string 共享存储卷的名称
spec.volumes[].emptyDir object 类型为empty Dir 的存储卷, 表示与Pod 同生命周期的一个临时目录,其值为一个空对象: emptyDir: {}
spec. volumes[] .hostPath object 类型为hostPath 的存储卷,表示挂载Pod 所在宿主机的目录,通过volumes[]. hostPath.path 指定
spec.volumes[].hostPath.path object Pod 所在主机的目录,将被用于容器mount 的目录
s pec.volumes[].secret object 类型为secret 的存储卷, 表示接载集群预定义的
secret 对象到容器内部
spec.volumes[].configMap object 类型为configMap 的存储卷, 表示挂载集群预定
义的configMap 对象到容器内部
spec.volumes[].livenessProbe object 对Pod 内各容器健康检查的设置,当探测无响应几次之后,系统将自动军启该容器。可以设置的方法包括: exec、httpGet 和tcpSocket. 对一个容器仅帘设置一种健康检查方法
spec.volumes[].livenessProbe<br />.exec object 对Pod 内各容器健康检查的设置, exec 方式
spec.volumes[].livenessProbe<br />.exec.command[] string exec 方式需要指定的命令或者脚本
spec.volumes[].livenessProbe<br />.httpGet object 对Pod 内各容器健康检查的设置, HTIPGet 方式.
需指定pa由、port
spec.volumes[].livenessProbe<br />.tcpSocket object 对Pod 内各容器健康枪查的设置, tcpSocket 方式
spec.volumes[].livenessProbe<br />.initialDelaySeconds number 容器启动完成后进行首次探测的时间,单位为s
spec.volumes[].livenessProbe<br />.timeoutSeconds number 对容器健康检查的探测等待响应的超时时间设
置,单位为s ,默认值为l s. 超过该超时时间设置,
将认为该容德不健康,将重启该容器
spec.volumes [].livenes sProbe.periodSeconds number 对容器健康检查的定期探测时间设置,单位为s,默认为! 10s 探测一次
spec.restartPolicy string Pod 的重启策略,可选值为A lways 、OnFail ure,
默认值为A lw ays.
spec .nodeSelector object 设置NodeSelector 表示将该Pod 调度到包含这些label 的Node 上,以key:valu e 格式指定
spec.imagePullSecrets Object Pull 镜像时使用的secret 名称,以name :secretkey格式指定
spec.hostNetwork boolean 是否使用主机网络模式,默认值为臼lse ,如果设
置为true ,则表示容器使用宿主机网络,不再使用
Docker 网桥,该Pod 将无法在同一台宿主机上启
动第2 个副本

(2) pod的使用

​ 在使用Docker 时,可以使用docker run 命令创建井启动一个容器。而在Kubemetes 系统中对长时间运行容器的要求是: 其主程序需要一直在前台执行。如果我们创建的Docker 镜像的启
动命令是后台执行程序,例如Linux 脚本:
nohup . /s tart.sh &
则在kubelet 创建包含这个容器的Pod 之后运行完该命令, 即认为Pod 执行结束,将立刻销毁该Pod 。故在制作镜像时,启动命令直接前台启动对于那些无法改造为前台执行的应用,可以是哟个supervisor辅助进行前台运行功能。

  • 静态Pod

​ 静态Pod 是由阳b elet 进行管理的仅存在于特定Node 上的Pod 。它们不能通过API Server进行管理, 无法与ReplicationController、Deployment 或者DaemonSet 进行关联, 井且kubele t
也无法对它们进行健康检查。静态Pod 总是由kubelet 进行创建的,并且总是在kubelet 所在的
Node 上运行的。

​ 创建静态Pod有两种方式:配置文件方式和HTTP方式。

  • Pod容器共享volume

​ 在同一个Pod 中的多个容器能够共享Pod 级别的存储卷Volume 。Volume 可以被定义为各种类型,多个容器各自进行挂载操作,将一个volume 挂载为容器内部需要的目录

(3)Pod的配置管理 —ConfigMap

  • 概述

    • 生成为为容器内的环境变量
    • 设置容器启动命令的启动参数(需设置为环境变量)
    • 以volume的形式挂载为容器内部的文件或目录

    ConfigMap 以一个或多个key: value 的形式保存在Kubemetes 系统中供应用使用,既可以用于表示一个变量的值(例如apploglevel=info ),也可以用于表示一个完整配置文件的内容。可以通过yaml文件或直接使用kubectl create configmap 命令行的方式来创建ConfigMap。

  • 创建ConfigMap资源对象

    yaml方式

apiversion: v1
kind: ConfigMap
metadata:
    name: my-appvars
data:
    apploglevel: info
    appdatadir: /var/data
   
通过kubectl 命令行方式创建
通过kubectl create configmap 创建
(1)通过一from-file 参数从文件中进行创建,可以指定key 的名称,也可以在一个命令行中创建包含多个key 的ConfigMap ,语法为:
 kubectl create configmap NAME --from-file=[key=]source --from-file=[key=]source
 例:kubectl create confiqmap cm-server.xml --from-file=server.xml 
(2)通过--from-file 参数从目录中进行创建,该目录下的每个配置文件名都被设置为key.文件的内容被设置为va lue ,语法为:
 kubectl create configmap NAME --from-file=config-files-dir
 例:kubectl create configmap cm-appconf - -from-file=configfiles    #configfiels 是目录
 (3)(3) --from-literal 从文本中进行创建,直接将指定的key=value创建为ConfigMap 的内容,
语法为:
  kubectl create configmap NAME --from-l iteral=keyl=valuel --from-literal=key2=value2
  例:kubectl create configmapαn-appenv --from-literal =loglevel=info --from-literal=appdatadir=/var/data
  • 容器应用ConfigMap

    1)通过环境变量方式使用ConfigMap

# 创建

apiVersion: v1
kind: COnfigMap
metadata:
  name: cm-appvars
  
data:
  apploglevel: info             #key: value
  appdatadir: /var/data
  
调用:
...
spec:
  containers:
  - name:
    image:
    command
    env:
    - name: APPLOGLEVEL
      valueFrom:
        configMapKeyRef:
            name: cm-appvars   #环境变量的值取自cm-appvars
            key: apploglevel    #对应的cm-appvars中的key

​ 2) 通过volumeMount使用ConfigMap

cat cm-appconfigfiles.yaml
# 创建ConfigMap资源对象
apiVersiob: v1
kind: ConfigMap
metadata:
    name: cm-serverxml
data:
  key-serverxml: |
    <?xml version='1.0' encoding='utf-8'?>
    ...
  key-loggingproperties: "handlers=..,"
  
# volumeMounts挂载
spec:
  containers:
  - name:
    image:
    ports:
    volumeMonunts:
    - name: serverxml           #引用volume中的那个卷
      mountPath: /configfiles   # 挂载高容器内的目录
  volume: 
  - name: serverxml             # 定义volume名
    configMap:
      name: cm-appconfigfiles   # 使用的ConfigMap名称
      items:
      - key: key-serverxml      # 对应ConfigMap中的key
        path: server.xml        # 值挂载的文件名,及值写入到容器中的什么文件中
      - key: key-logging.properties
        path: logging.properties
  
如果不指定items,则使用volumeMount 方式在容器内的目录生成每个key名称对应的文件。
  • 使用ConfigMap 的限制条件
    • ConfigMap 必须在Pod 之前创建
    • ConfigMap 受Namespace 限制,只有处于相同Namespaces 中的Pod 可以引用它。
    • ConfigMap 中的配额管理还未能实现。
    • kubelet 只支持可以被API Server 管理的Pod 使用ConfigMap 。kubelet 在本Node 上通
      过--mainfest-url 或--config 自动创建的静态P od 将无法引用Conf1gMap 。
    • 在Po d 对ConfigMap 进行挂载( volumeMount )操作时,容器内部只能挂载为“目录”,
      无法挂载为“文件”

(3) 在容器中获取Pod信息

Downward API 可以通过以下两种方式将Pod 信息注入容器内部。

在某些集群中,集群中的每个节点都需要将自身的标识( ID )及进程绑定的IP 地址等信息事先写入配置文件中,进程启动时读取这些信息,然后发布到某个类似服务注册中心的地方,以实现集群节点的自动发现功能。此时Downward API 就可以派上用场了,具体做法是先编写
一个预启动脚本或Init Container,通过环境变量或文件方式获取Pod 自身的名称、IP 地址等信息,然后写入主程序的配置文件中, 最后启动主程序。

  • 环境变量::用于单个变量,可以将Pod 信息和Container 信息注入容器内部。
apiVersion: v1
kind: Pod
metadata:
  name: dapi-test-pod
spec:
  containers:
  - name:
    image:
    command:
    ports:
    env:
      - name: MY_POD_NAME
        valumeFrom:
          fieldRef:
            fieldPath: metadata.name
      - name: MY_POD_NAMESPACE
        valueFrom:
          fieldRef:
            fieldPath: metadata.namespace
      - name: MY_POD_IP
        valumeFrom:
          fieldRef:
            fieldPath: status.podIp
【Downward API提供的变量】
metadata.name: Pod 的名称,当Pod 通过RC 生成时,其名称是RC 随机产生的唯一名称。

status.podIP: Pod 的回地址,之所以叫作status.podIP 而非metadata.IP , 是因为Pod 的IP 属于状态数据,而非元数据。

metadata.namespace: Pod 所在的Namespace

requests.cpu :容器的CPU 请求值

limits.cpu : 容器的CPU 限制值

requests.memory :容器的内存请求值。

  • Volume挂载将数组类信息生成为文件,挂载到容器内部
...
metadata:
  name:
  labels:
    zone: us-est-coast
    cluster: test-cluster1  
  annotations:
    build: two
    builder: john-doe
    
    ...
    volumeMounts:
      - name: podinfo
        mountPath: /etc
        readOnly: false
  volume:
    - name: podinfo
      downwardAPI:
        items:
          - path: "labels"
          fieldRef:
            fieldPath: metadata.labels
          - path: "annotations"
          fieldRef:
            fieldPath: metadata.annotations
注意volumes 中downwardAPI的特殊语法, 通过items 的设置,将会以path 的名称生成文件。这里将在容器内生成/etc/labels 和/etc/annotations 两个文件, /etc/ labels 中将包含
metadata.labels 的全部Labl 列表,/etc/annotations 中将包含metadata.annotations 的全部Label列表。

(4) pod什么周期和重启策略

  • Pending:APIServer 己经创建该Pod , 但Pod 内还有一个或多个容器的镜像没有创建,包括正在下我镜像的过程

  • Running:Pod 内所有容器均己创建,且至少有一个容器处于运行状态、正在启动状态或正在亟启状态

  • Succeeded:Pod 内所有容器均成功执行退出, 且不会再重启

  • Failed:Pod 内所有容器均已退出,但至少有一个容器退出为失败状态

  • Unknown:由于某种原因无法获取该Pod 的状态, 可能由于网络通信不畅导致

Pod 的重启策略包括Always 、OnFailure 和Never, 默认值为A lways

(5)Pod健康检查

  • LivenessProbe 探针:用于判断容器是否存活( running 状态),如果LivenessProbe 探针探测到容器不健康,则kubelet 将杀掉该容器,并根据容器的重启策略做相应的处理。如果一个容器不包含LivenessProbe 探针,那么kubelet 认为该容器的LivenessProbe 探 针返回的值永远是“ Success"
    1)ExecAction实现方式
在容器内部执行一个命令,如果该命令的返回码为0,则表示容器健康。

...
spec:
  containers:
  - name:
    image:
    args:
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/health
        initialDelaySeconds: 15     # 健康检查的初始探测时间s.启动容器后进行首次健康检查的等待时间
        timeoutSeconds: 1       #健康检查发送请求后等待响应的超时时间s. 当超时发生时,kubelet会认为容已经法法提供服务,将会重启改容器。

2)TCPSocketAction实现方式

通过容器的IP地址和端口号指定TCP检查,如果能建立TCP连接,则表明容器健康。

...
spec:
  containers:
  - name:
    image:
    ports:
    livenessPorbe:
      tcpSocket:
        port: 80
      initialDelaySeconds: 30
      timeoutSeconds: 1

3)HTTPG etAc tion实现方式

通过容器的IP地址,端口号,及路径调用HTTP get方法,如果响应的状态码大于等于200且小于400,则认为容器装填健康。

spec:
  containers:
  - name: 
    image:
    ports:
    livenessProbe:
      httpGet:
        path: /_status/healthz
        port: 80
      initialDelaySeconds: 30
      timeoutSeconds: 1
  • ReadinessProbe 探针:用于判断容器是否启动完成( ready 状态),可以接收请求。如果ReadinessProbe 探针检测到失败,则Pod 的状态将被修改。Endpoint Con位oiler 将从Service 的Endpoint 中删除包含该容器所在Pod 的Endpoint 。

(6) Pod 调度

  • Deployment/RC 全自动调度到node节点

Deployment 或RC 的主要功能之一就是自动部署一个容器应用的多份副本, 以及持续监控副本的数量, 在集群内始终维持用户指定的副本数量

  • NodeSelector:定向调度

通过Node的标签和Pod的nodeSelector属性相匹配,来实现定向调度。

node打标签:kubectl label nodes <node-name> <label -key>=<label-value >

...

spec.nodeSelector:

如果给多个node都定义了相同的标签,则scheduler将会根据调度算法 从这组node中挑选一个可用的node进行pod调度。

  • NodeAffinity: node亲和性调度

    • RequiredDuringSchedulinglgnoredDuringExecution :必须满足指定的规则才可以调度Pod
      到Node 上(功能与nodeSelector 很像,但是使用的是不同的语法),相当于硬限制。
    • PreferredDuringSchedulinglgnoredDuringExecution :强调优先满足指定规则,调度器会
      尝试调度Pod 到Node 上,但并不强求,相当于软限制。多个优先级规则还可以设置权
      重( weight )值,以定义执行的先后顺序。

    IgnoredDuringExecution的意思是:如果一个Pod 所在的节点在Pod 运行期间标签发生了变
    更,不再符合该Pod 的节点亲和性需求,则系统将忽略Node 上Label 的变化,该Pod 能继续在
    该节点运行。

...
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingignoredDuringExecution:
        ...
      preferredDuringSchedulingign.redDuringExecution:
        ...
  • PodAffinity:pod亲和与互斥调度策略调度

根据节点上正在运行的Pod 的标签而不是节点的标签进行判断和调度, 要求对节点和Pod 两个条件进行匹配。

  • Pod互斥性调度
  • Taints 和Tolerations(污点和容忍)

Taint污点,让node拒绝pod的运行。Taint 需要和Toleration 配合使用,让Pod 避开那些不合适的Node。在node上设置一个或多个Taint之后,除非Pod明确什么能容忍这些污点,否则无法在这些Node上运行。
Pod 的Toleration 声明中的key 和effect 需要与Taint 的设置保持一致,井且满足以下条件
之一。如果不指定operator ,则默认值为Equal

1)operator 的值是Exists (无须指定value )

2)operator 的值是Equal 井且value 相等。

Kubernetes调度器处理多个Taint 和Toleration 的逻辑顺序为: 首先列出节点中所有的Ta int ,然后忽略Pod
的Toleration 能够匹配的部分,剩下的没有忽略掉的Taint 就是对Pod 的效果了.

1)如果剩余的Taint 中存在effect=NoSchedule ,则调度器不会把该Pod 调度到这一节点上

2)如果剩余Taint 中没有NoSchedule 效果, 但是有PreferNoSch edul e 效果,则调度器会尝
试不把这个Pod 指派给这个节点。

3)如果剩余Taint 的效果有NoExecute 的, 并且这个Pod 已经在该节点上运行,则会被驱
逐; 如果没有在该节点上运行,也不会再被调度到该节点上

独占节点

kubectl taint nodes nodename dedicated=groupName:NoSchedule,然后给这些应用的Pod 加入对应的Toleration,这样,带有合适Toleration 的Pod 就会被允许同使用其他节点一样使用有Taint 的节点。

具有特殊硬件设备的节点

kubectl taint nodes nodename special=true : NoSchedule

kubectl taint nodes nodename special=true:PreferNoSchedule

然后在Pod 中利用对应的Toleration 来保障特定的Pod 能够使用特定的硬件。

定义Pod驱逐行为,以应对节点故障

(8) Job 批处理调度

若要使用参阅Kubernetes权威指南p141

(9) Cronjob定时任务

若要使用参阅Kubernetes权威指南p145

(10) 自定义调度器

(11)Init Container 初始化容器

用于在启动应用容器之前启动一个或多个初始化容器,完成应用容器的预置条件,初始化容器运行一起就结束任务,并且必须在成功执行完成后,系统才能继续执行下一个容器。

...
spec:
  initContainers:
  - name:
  ...
  containers:

( 1 ) init container 的运行方式与应用容器不同,它们必须先于应用容器执行完成, 当设置了
多个init container 时,将按顺序逐个运行,并且只有前一个init container 运行成功后才能运行后
一个init container 。当所有init container 都成功运行后, Kubemetes 才会初始化Pod 的各种信息,
并开始创建和运行应用容器。

(2 )在init container 的定义中也可以设置资源限制、volume 的使用和安全策略, 等等。但资源限制的设置与应用容器略有不同。

(3) init container 不能设置readinessProbe 探针,因为必须在它们成功运行后才能继续运行Pod 中定义的普通容器。

(12) Pod的升级和回滚

  • Deployment的升级:可以在运行时修改Deployment 的Pod 定义(spec.template )或镜像名称,井应用到Deployment 对象上,系统即可完成Deployment 的自动更新操作。如果在更新过程中发生了错误, 则还可以通过回滚( Rollback )操作恢复Pod的版本。在创建Deployment 时使用--record 参数(kubectl create -f filename.yaml --record=true)

1)升级

eg:kubectl set image deployment/nginx-deployment nginx=nginx:l . 9.1

kubectl set image deployment/deployment_name container_name=new_image

or

eg:kubectl edit deployment/nginx-deployment

2)升级策略

RollingUpdate滚动更新:默认更新模式。设置spec.strateg予type=RollingUpdate。spec.strategy.rollingUpdate.maxUnavailable参数用于指定在更新过程中不可用状态pod数量的上限。

s pe c.strategy.rollingUpdate .maxSurge参数用于指定Deployment 更新Pod 过程中Pod 总数超
过Pod 期望副本数部分的最大值

Recreate重建:设置spec. strategy. type= Recreate

3)回滚

查看部署历史记录:kubectl rollout history deployment/deployment_name。当且仅当Deployment的Pod模板被更改时才会创建修订版本。

回滚到指定版本:kubectl rollout undo deployment/nginx-deployment --to-revision=2

4)暂停和恢复:对于一次复杂的Deployment 配置修改,为了避免频繁触发Deployment 的更新操作,可以
先暂停Deployment 的更新操作,然后进行配置修改,再恢复Deployment。

暂停:kubectl rollout pause deployment/deployment_name

修改:kubectl set image deploy/nginx-deployment nginx=nginx:1.9.1 or edit编辑

恢复:kubectl rollout resume deploy deployment_name

  • RC的升级

3、Pod深入掌握

至179

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容