https://blog.csdn.net/keysilence1/article/details/70239717

概念

Kubernetes是谷歌严格保密十几年的秘密武器——Borg的一个开源版本,是Docker分布式系统解决方案。

名词

  • Borg 
    Borg是谷歌内部使用的大规模集群管理系统,基于容器技术,目的是实现资源管理的自动化,以及跨多个数据中心的资源利用率的最大化;
  • Endpoint(IP+Port) 
    标识服务进程的访问点;
  • Master 
    集群控制节点,负责整个集群的管理和控制,基本上Kubernetes所有的控制命令都是发给它,它来负责具体的执行过程,我们后面所有执行的命令基本都是在Master节点上运行的; 
    • Kubernetes API Server(kube-apiserver),提供Http Rest接口的关键服务进程,是Kubernetes里所有资源的增、删、改、查等操作的唯一入口,也是集群控制的入口进程;
    • Kubernetes Controller Manager(kube-controller-manager),Kubernetes里所有资源对象的自动化控制中心,可以理解为资源对象的“大总管”;
    • Kubernetes Scheduler(kube-scheduler),负责资源调度(Pod调度)的进程,相当于公交公司的“调度室”;
    • etcd Server,Kubernetes里所有的资源对象的数据全部是保存在etcd中;
  • Node 
    除了Master,Kubernetes集群中的其他机器被称为Node节点,Node节点才是Kubernetes集群中的工作负载节点,每个Node都会被Master分配一些工作负载(Docker容器),当某个Node宕机,其上的工作负载会被Master自动转移到其他节点上去; 
    • kubelet,负责Pod对应的容器的创建、启停等任务,同时与Master节点密切协作,实现集群管理的基本功能。一旦Node被纳入集群管理范围,kubelet进程就会想Master几点汇报自身的情报,这样Master可以获知每个Node的资源使用情况,并实现高效均衡的资源调度策略。而某个Node超过指定时间不上报信息,会被Master判定为“失联”,Node状态被标记为不可用(Not Ready),随后Master会触发“工作负载大转移”的自动流程;
    • kube-proxy,实现Kubernetes Service的通信与负载均衡机制的重要组件;
    • Docker Engine(docker),Docker引擎,负责本机的容器创建和管理工作;
  • Pod 

    • 每个Pod都有一个特殊的被称为“根容器”的Pause容器,还包含一个或多个紧密相关的用户业务容器;
    • 一个Pod里的容器与另外主机上的Pod容器能够直接通信;
    • 如果Pod所在的Node宕机,会将这个Node上的所有Pod重新调度到其他节点上;
    • 普通Pod及静态Pod,前者存放在etcd中,后者存放在具体Node上的一个具体文件中,并且只能在此Node上启动运行;
    • Docker Volume对应Kubernetes中的Pod Volume;
    • 每个Pod可以设置限额的计算机资源有CPU和Memory; 
      • Requests,资源的最小申请量;
      • Limits,资源最大允许使用的量;


  • Event 
    是一个事件记录,记录了事件最早产生的时间、最后重复时间、重复次数、发起者、类型,以及导致此事件的原因等信息。Event通常关联到具体资源对象上,式排查故障的重要参考信息;
  • Label 
    Label可以附加到各种资源对象上,一个资源对象可以定义任意数量的Label。给某个资源定义一个Label,相当于给他打一个标签,随后可以通过Label Selector(标签选择器)查询和筛选拥有某些Label的资源对象。我们可以通过给指定的资源对象捆绑一个或多个Label来实现多维度的资源分组管理功能,以便于灵活、方便的进行资源分配、调度、配置、部署等管理工作; 
    Label Selector示例:select * from pod where pod’s name=’XXX’,env=’YYY’,支持操作符有=、!=、in、not in;
  • Replication Controller(RC) 
    部署和升级Pod,声明某种Pod的副本数量在任意时刻都符合某个预期值; 
    • Pod期待的副本数;
    • 用于筛选目标Pod的Label Selector;
    • 当Pod副本数量小于预期数量的时候,用于创建新Pod的Pod模板(template);
  • Replica Set 
    下一代的Replication Controlle,Replication Controlle只支持基于等式的selector(env=dev或environment!=qa)但Replica Set还支持新的、基于集合的selector(version in (v1.0, v2.0)或env notin (dev, qa)),这对复杂的运维管理带来很大方便。
  • Deployment 
    拥有更加灵活强大的升级、回滚功能。在新的版本中,官方推荐使用Replica Set和Deployment来代替RC,两者相似度>90%,相对于RC一个最大升级是我们随时指导当前Pod“部署”的进度。Deployment使用了Replica Set,除非需要自定义升级功能或根本不需要升级Pod,一般情况下,我们推荐使用Deployment而不直接使用Replica Set; 
    典型使用场景: 
    • 创建一个Deployment对象来生成对应的Replica Set并完成Pod副本的创建过程;
    • 检查更新Deployment的状态来查看部署动作是否完成(Pod副本的数量是否达到预期的值);
    • 更新Deployment以创建新的Pod;(比如镜像升级)
    • 如果当前Deployment不稳定,则回滚到一个早先的Deployment版本;
    • 挂起或者回复一个Deployment;
  • Horizontal Pod Autoscaler(HPA) 
    意思是Pod横向自动扩容,目标是实现自动化、智能化扩容或缩容。 
    Pod负载度量指标: 
    • CPUUtilizationPercentage 
      通常使用一分钟内的平均值,可以通过Heapster扩展组件获取这个值。一个Pod自身的CPU利用率是该Pod当前CPU的使用量除以它的Pod Request的值。例如Pod Request定义值为0.4,当前Pod使用量为0.2,则它的CPU使用率为50%。但如果没有定义Pod Request值,则无法使用CPUUtilizationPercentage来实现Pod横向自动扩容的能力;
    • 应用程序自定义的度量指标,比如服务在每秒内的相应的请求书(TPS或QPS)
  • Service 
    Service其实就是我们经常提起的微服务架构中的一个“微服务”,通过分析、识别并建模系统中的所有服务为微服务——Kubernetes Service,最终我们的系统由多个提供不同业务能力而又彼此独立的微服务单元所组成,服务之间通过TCP/IP进行通信,从而形成了我们强大而又灵活的弹性网络,拥有了强大的分布式能力、弹性扩展能力、容错能力; 

    如图示,每个Pod都提供了一个独立的Endpoint(Pod IP+ContainerPort)以被客户端访问,多个Pod副本组成了一个集群来提供服务,一般的做法是部署一个负载均衡器来访问它们,为这组Pod开启一个对外的服务端口如8000,并且将这些Pod的Endpoint列表加入8000端口的转发列表中,客户端可以通过负载均衡器的对外IP地址+服务端口来访问此服务。运行在Node上的kube-proxy其实就是一个智能的软件负载均衡器,它负责把对Service的请求转发到后端的某个Pod实例上,并且在内部实现服务的负载均衡与会话保持机制。Service不是共用一个负载均衡器的IP地址,而是每个Servcie分配一个全局唯一的虚拟IP地址,这个虚拟IP被称为Cluster IP。
  • Node IP 
    Node节点的IP地址,是Kubernetes集群中每个节点的物理网卡的IP地址,是真是存在的物理网络,所有属于这个网络的服务器之间都能通过这个网络直接通信;
  • Pod IP 
    Pod的IP地址,是Docker Engine根据docker0网桥的IP地址段进行分配的,通常是一个虚拟的二层网络,位于不同Node上的Pod能够彼此通信,需要通过Pod IP所在的虚拟二层网络进行通信,而真实的TCP流量则是通过Node IP所在的物理网卡流出的;
  • Cluster IP 
    Service的IP地址。特性如下: 
    • 仅仅作用于Kubernetes Servcie这个对象,并由Kubernetes管理和分配IP地址;
    • 无法被Ping,因为没有一个“实体网络对象”来响应;
    • 只能结合Service Port组成一个具体的通信端口;
    • Node IP网、Pod IP网域Cluster IP网之间的通信,采用的是Kubernetes自己设计的一种编程方式的特殊的路由规则,与IP路由有很大的不同;
  • Volume 
    可以通过如下命令查看Volume信息: 

注:Node、Pod、Replication Controller和Service等都可以看作是一种“资源对象”,几乎所有的资源对象都可以通过Kubernetes提供的kubectl工具执行增、删、改、查等操作并将其保存在ectd中持久化存储。

优点

  • 轻装上阵,小团队即可轻松应付从设计实现到运维的复杂的分布式系统;
  • 全面拥抱微服务架构;
  • 迁移方便,可以很方便的搬迁到公有云或基于OpenStack的私有云上;
  • 超强的横向扩容能力;

示例

环境准备

系统

64位CentOS7

安装Kubernetes

关闭防火墙(没安装防火墙就算了~)

systemctl disable firewalld
systemctl stop firewalld
  • 1
  • 2

安装etcd和Kubernetes软件(会自动安装Docker软件)

yum install -y etcd kubernetes
  • 1

安装完毕后,需要修改如下两个配置文件: 
* 修改/etc/sysconfig/docker,将其中OPTIONS内容设置为:OPTIONS=’–selinux-enabled=false –insecure-registry grc.io’; 
* 修改/etc/kubernetes/apiserver,把–admission-control参数的ServiceAccount删除;

启动所有服务

systemctl start etcd
systemctl start docker
systemctl start kube-apiserver
systemctl start kube-controller-manager
systemctl start kube-scheduler
systemctl start kubelet
systemctl start kube-proxy
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如果不确定服务是否启动成功,可以运行下面命令进行一一确认

ps aux | grep 服务名
  • 1

Replication Controller

Java Web应用 
注:Tomcat有可能无法正常启动,原因是虚机的内存和CPU设置过小,请酌情调大!

镜像

下载地址

https://hub.docker.com/r/kubeguide/tomcat-app/

拉取
Tomcat镜像

docker pull kubeguide/tomcat-app:v2

Mysql镜像

docker pull daocloud.io/library/mysql:latest

构建Mysql RC定义文件(构建创建Pod的源文件)

命名

mysql-rc.yaml

内容
apiVersion: v1
kind: ReplicationController
metadata:
name: mysql
spec:
replicas: 1
selector:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
发布到Kubernetes集群
创建RC
kubectl create -f mysql-rc.yaml
  • 1
查看RC
kubectl get rc
  • 1
查看Pod
kubectl get pods
  • 1

构建Mysql Kubernetes Service定义文件

命名

mysql-svc.yaml

内容
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
selector:
app: mysql
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
创建
kubectl create -f mysql-svc.yaml
  • 1
查看SVC
kubectl get svc
  • 1

构建Tomcat RC定义文件

命名

myweb-rc.yaml

内容
kind: ReplicationController
metadata:
name: myweb
spec:
# Pod的数量
replicas: 1
# spec.selector与spec.template.metadata.labels,这两个字段必须相同,否则下一步创建RC会失败。
selector:
app: myweb
template:
metadata:
labels:
app: myweb
# 容器组的定义
spec:
containers:
# 容器名称
- name: myweb
# 容器对应的镜像
image: kubeguide/tomcat-app:v1
ports:
# 在8080端口上启动容器进程,PodIP与容器端口组成Endpoint,代表着一个服务进程对外通信的地址
- containerPort: 8080
env:
#此处如果在未安装域名解析的情况下,会无法将mysql对应的IP解析到env环境变量中,因此先注释掉!
# - name: MYSQL_SERVICE_HOST
# value: 'mysql'
- name: MYSQL_SERVICE_PORT
value: '3306'
  • 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
发布到Kubernetes集群
创建RC
kubectl create -f myweb-rc.yaml
  • 1
查看RC
kubectl get rc
  • 1
查看Pod
kubectl get pods
  • 1

构建Tomcat Kubernetes Service定义文件

命名

myweb-svc.yaml

内容
apiVersion: v1
kind: Service
metadata:
name: myweb
spec:
type: NodePort
ports:
- port: 8080
nodePort: 30001
selector:
app: myweb
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
创建
kubectl create -f myweb-svc.yaml
  • 1
查看SVC
kubectl get services
  • 1

运行

浏览器中输入http://虚拟机IP:30001/demo即可呈现如下内容:

Deployment

构建Deployment定义文件

命名

tomcat-deployment.yaml

内容

#与RC不同之处,版本配置不同
apiVersion: extensions/v1beta1
#与RC不同之处,Kind不同
kind: Deployment
metadata:
name: frontend
spec:
replicas: 1
selector:
matchLabels:
tier: frontend
matchExpressions:
- {key: tier, operator: In, values: [frontend]}
template:
metadata:
labels:
app: app-demo
tier: frontend
spec:
containers:
- name: tomcat-demo
image: tomcat
# 设置资源限额,CPU通常以千分之一的CPU配额为最小单位,用m来表示。通常一个容器的CPU配额被定义为100~300m,即占用0.1~0.3个CPU;
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
  • 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

发布到Kubernetes集群

创建Deployment

kubectl create -f tomcat-deployment.yaml
  • 1

查看Deployment

kubectl get deployments
  • 1

  • DESIRED,Pod副本数量的期望值,及Deployment里定义的Replica;
  • CURRENT,当前Replica实际值;
  • UP-TO-DATE,最新版本的Pod的副本数量,用于指示在滚动升级的过程中,有多少个Pod副本已经成功升级;
  • AVAILABLE,当前集群中可用的Pod的副本数量;

查看对应的Replica Set

kubectl get rs
  • 1

看一下这里的名称与Deployment里面名称的关系;

查看Pod

kubectl get pods
  • 1

看一下这里Pod的命名以Deployment对应的Replica Set的名字为前缀;

查看Pod的水平扩展过程

kubectl describe deployments
  • 1

HPA

构建HPA定义文件

命名

php-apache.yaml

内容

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: php-apache
namespace: default
spec:
maxReplicas: 10
minReplicas: 1
scaleTargetRef:
kind: Deployment
name: php-apache
targetCPUUtilizationPercentage: 90
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

这个HPA控制的目标对象为一个名叫php-apache的Deployment里的Pod副本,当这些Pod副本的CPUUtilizationPercentage超过90%时会触发自动扩容行为,扩容或缩容时必须满足的一个约束条件是Pod的副本数要介于1与10之间;

命令方式实现相同的功能

kubectl autoscale deployment php-apache –cpu-percent=90 –min=1 –max=10

Service

构建Service定义文件

命名

tomcat-service.yaml

内容

apiVersion: v1
kind: Service
metadata:
name: tomcat-service
spec:
# 服务如果想被外部调用,必须配置type
type: NodePort
ports:
- port: 8080
name: service-port
# 服务如果想被外部调用,必须配置nodePort
nodePort: 31002
- port: 8005
name: shutdown-port
selector:
tier: frontend
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

上述内容定义了一个名为“tomcat-service”的Servcie,它的服务端口为8080,拥有“tier=frontend”这个Label的所有Pod实例都属于它; 
这里的NodePort没有完全解决外部访问Service的所有问题,比如负载均衡,假如我们又10个Node,则此时最好有一个负载均衡器,外部的请求只需访问此负载均衡器的IP地址,由负载局衡器负责转发流量到后面某个Node的NodePort上。这个负载均衡器可以是硬件,也可以是软件方式,例如HAProxy或者Nginx; 
如果我们的集群运行在谷歌的GCE公有云上,那么只要我们把Service的type=NodePort改为type=LoadBalancer,此时Kubernetes会自动创建一个对应的LoadBalancer实例并返回它的IP地址供外部客户端使用。其它公有云提供商只要实现了支持此特性的驱动,则也可以达到上述目的;

发布到Kubernetes集群

创建Servcie

kubectl create -f tomcat-service.yaml 
  • 1

查看Endpoint列表

kubectl get endpoints
  • 1

查看tomcat-service更多信息

命令
kubectl get svc tomcat-service -o yaml
  • 1
结果
apiVersion: v1
kind: Service
metadata:
creationTimestamp: 2017-04-21T15:47:43Z
name: tomcat-service
namespace: default
resourceVersion: "227916"
selfLink: /api/v1/namespaces/default/services/tomcat-service
uid: dbf15b30-26a9-11e7-b185-080027d589d3
spec:
# Kubernetes集群内部的地址,无法在集群外部使用这个地址
clusterIP: 10.254.2.210
ports:
# 服务的虚端口
- port: 8080
protocol: TCP
# 确定提供该服务的容器所暴露的端口号,默认与port相同
targetPort: 8080
selector:
tier: frontend
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

补充命令

查看已存在的镜像

docker images
  • 1

删除某个已存在的镜像

docker rmi 镜像ID
  • 1

查看当前启动的镜像

docker ps
  • 1

命令行方式进入某个容器

docker exec -it 容器ID sh
  • 1

查看某个容器日志

docker logs 容器ID
  • 1

删除某个运行的容器

docker rm -f 容器ID
  • 1

yaml文件修改后应用

kubectl apply -f XXX.yaml
  • 1

重新启动基于yaml文件的应用

kubectl delete -f XXX.yaml
kubectl create -f XXX.yaml
  • 1
  • 2

查看集群中有多少Node

kubectl get nodes
  • 1

查看某个Node的详细信息

kubectl describe node 节点名
  • 1

动态修改副本数量

kubectl scale rc XXX --replicas=3
  • 1

查看RC的详细信息

kubectl describe rc 标签名或者选择器名
  • 1

通过RC修改Pod副本数量

kubectl replace -f rc.yaml

kubect edit replicationcontroller replicationcontroller名
  • 1
  • 2
  • 3

对RC使用滚动升级,来发布新功能或修复BUG

kubectl rolling-update replicationcontroller名 --image=镜像名
  • 1

滚动升级

kubectl rolling-update replicationcontroller名 -f XXX.yaml

Kubernetes权威指南学习笔记(一)的更多相关文章

  1. HTTP权威指南-学习笔记

    目录 HTTP权威指南-学习笔记 HTTP: Web的基础 URL与资源 HTTP报文 连接管理 HTTP结构 Web服务器 代理 缓存 集成点: 网关,隧道及中继 Web机器人 识别,认证与安全 客 ...

  2. JavaScript 权威指南-学习笔记(一)

    本文所有教程及源码.软件仅为技术研究.不涉及计算机信息系统功能的删除.修改.增加.干扰,更不会影响计算机信息系统的正常运行.不得将代码用于非法用途,如侵立删! ## JavaScript 权威指南-学 ...

  3. CSS权威指南学习笔记系列(1)CSS和文档

    题外话:HTML是一种结构化语言,而CSS是它的补充:这是一种样式语言.CSS是前端三板斧之一,因此学习CSS很重要.而我还是菜鸟,所以需要加强学习CSS.这个是我学习CSS权威指南的笔记,如有不对, ...

  4. Hadoop权威指南学习笔记二

    MapReduce简单介绍 声明:本文是本人基于Hadoop权威指南学习的一些个人理解和笔记,仅供学习參考,有什么不到之处还望指出,一起学习一起进步. 转载请注明:http://blog.csdn.n ...

  5. Hadoop权威指南学习笔记一

    Hadoop简单介绍 声明:本文是本人基于Hadoop权威指南学习的一些个人理解和笔记,仅供学习參考,有什么不到之处还望指出.一起学习一起进步. 转载请注明:http://blog.csdn.net/ ...

  6. Hadoop权威指南学习笔记三

    HDFS简单介绍 声明:本文是本人基于Hadoop权威指南学习的一些个人理解和笔记,仅供学习參考.有什么不到之处还望指出,一起学习一起进步. 转载请注明:http://blog.csdn.net/my ...

  7. IDA Pro权威指南学习笔记(一)

    一直不懂逆向,最近刚好不忙,于是学习逆向,用来做笔记,顺便和大家分享交流. 参考书籍<IAD PRO权威指南> 工具: PETools: ETools 是另一款很好的PE文件编辑工具,以前 ...

  8. css权威指南学习笔记 —— css选择器

    1,选择器:选择器的一些基本常用规则基本都记得,w3c上都有,平时也常用,不常用的一些后代选择器经常就忘记了.一些归纳一下后代选择器,加深一下印象: a:子选择器:   p>a  a是直接是p的 ...

  9. maven权威指南学习笔记(五)—— POM

    1. 简介 Archetype插件通过 pom.xml 文件创建了一个项目.这就是项目对象模型 (POM),一个项目的声明性描述. 当Maven运行一个目标的时候,每个目标都会访问定 义在项目POM里 ...

随机推荐

  1. vc6.0出现“cannot add new member”解决办法

    在编辑一个工程的时候,添加一个按钮,对这个按钮产生消息函数 双击按钮之后出现 cannot add new member 网上说删除.clw文件 我发现并没有这个后缀的文件 以下是我的操作办法:   ...

  2. Python数据分析 EPD

    参考用书 <利用Python进行技术分析:Python for Data Analysis> 官方把epd (https://www.enthought.com/products/cano ...

  3. springboot整合图像数据库Neo4j

    百度百科: Neo4j是一个高性能的,NOSQL图形数据库,它将结构化数据存储在网络上而不是表中.它是一个嵌入式的.基于磁盘的.具备完全的事务特性的Java持久化引擎,但是它将结构化数据存储在网络(从 ...

  4. 【282】◀▶ arcpy.mapping 常用函数说明

    arcpy.mapping 教程入门 arcpy.mapping 指导原则 按字母顺序排序的 arcpy.mpping 类列表 按字母顺序排序的 arcpy.mpping 函数列表 按字母顺序排序的 ...

  5. c++多线程编程(一)

    C++本身并没有提供任何多线程机制,但是在windows下,我们可以调用SDK win32 api来编写多线程的程序,下面就此简单的讲一下: 创建线程的函数 HANDLE CreateThread( ...

  6. 8.INSERT INTO 语句 UPDATE 语句

    1. INSERT INTO 语句 INSERT INTO 语句用于向表格中插入新的行. 语法 INSERT INTO 表名称 VALUES (值1, 值2,....) INSERT INTO Per ...

  7. Luogu 4091 [HEOI2016/TJOI2016]求和

    BZOJ 4555 一道模板题. 第二类斯特林数有公式: $$S(n, m) = \frac{1}{m!}\sum_{i = 0}^{m}(-1)^i\binom{m}{i}(m - i)^n$$ 考 ...

  8. 3.Strings 字符串如何工作?----对缓冲区的理解。

    修改Hello World程序向特定的人问好. #include <iostream> #include <string> int main() { std::string n ...

  9. [GO]map做函数参数

    package main import "fmt" func test(m map[int]string) { delete(m, ) } func main() { m := m ...

  10. 图像读取Exif小知识,图像扶正,还原拍摄时的角度

    在做人脸识别的时候发现很多手机拍摄的图像在C#读取之后方向出现了错误,Bitmap中的宽度和实际的windows的文件属性内的参数相反,引起一阵测试和思考,后来百度出来可以用Exif来解决 githu ...