2020年6月20日星期六

孕期频繁孕吐,四招帮你缓解!

孕期频繁孕吐,四招帮你缓解!


不管是否有怀孕经验的女性,对怀孕以后的妊娠反应一定都有听说过或是经历过,恶心呕吐是公认的一种症状反应,这是由于女性怀孕后,体内的激素会发生变化,胎盘会分泌出一种人体绒毛膜促性腺激素,由于这种激素的增加会导致孕妇出现恶心呕吐,食欲不振等症状,当然症状也分大小有的,女性的孕期反应只是一点点,并不影响生活质量,而有的女性确实属于严重的孕吐现象,已经严重的威胁到了女性的生活与工作,因此需要找到方法进行缓解,通过什么缓解孕吐比较有效果?


怎么缓解孕吐效果更好?

1、孕吐是正常情况,不要过度紧张

每个孕妇都会有这样的经历,刚刚得知怀孕的消息还没有从惊喜中回过神就已经开始接受孕吐的困扰。老人们会把孕吐这种症状称之为害喜,似乎好像是每一个孕妈妈不可避免的孕期过程。导致孕吐的主要原因与体内激素发生变化有关系,这种激素并不是我们可以通过任何方式进行干预的,所以缓解孕吐的方法只是从表面有一丝丝作用,并不能彻底帮助孕妇免除孕吐的困扰。

2、调整饮食习惯,尽量避开孕吐时间进食

在怀孕期间尽可能的调理日常饮食,多吃较干的食物,比如饼干,馒头片,面包片,尽可能错开早上孕吐反应较大的阶段,选择中午或是晚上,避免吃什么吐什么的现象。如果孕妇孕吐情况比较严重,可以多吃蔬菜和水果,这些偏碱性的食物,能有效预防酸中毒,避免呕吐过重增加肠胃负担。


3、及时补充水分,避免脱水情况

在孕期,经常因为恶心呕吐的问题,很可能会导致孕妇出现脱水的现象,因此要适量补充水分,在喝水的时候不要猛喝,这样很容易把胃胀满,反而无法再继续使用其他食物。尽可能小口喝水这样能及时帮助身体补充水分,避免流失电解质。


官宣!CBA巨人杀手队启用新外援 将效仿广东单外援出战?_吉林队

官宣!CBA巨人杀手队启用新外援 将效仿广东单外援出战?_吉林队


原标题:官宣!CBA巨人杀手队启用新外援 将效仿广东单外援出战?

北京时间6月19日,距离CBA联赛重启还有一天的时间。吉林队最终决定官宣了,新外援肖恩-希尔将顶替琼斯的位置。而按照CBA联赛的规则,在希尔加盟以后,吉林队便不再是全华班球队,届时,他们将与广东队一样,选择单外援出战。

事实上,在琼斯和霍尔曼确定无法归来以后,吉林队便一直在积极寻找新外援人选。只不过,由于目前大部分外援都滞留在美国,吉林队可选择的空间并不大。在几经筛选后,吉林队最终还是选择冒险,让希尔顶替了琼斯的位置。

肖恩-希尔与他的前任琼斯比起来,无论是名气还是实力,都要略为逊色。据悉,在加盟吉林队之前,希尔并没有在中国征战过职业联赛,只打过一些野球场的比赛。而在海外联赛阅历上,他倒是先后在哈萨克斯坦、拉脱维亚等联赛效力过。本赛季,在亚美尼亚联赛,他场均还有22.1分8.1助进账。

本赛季,吉林队的战绩还是非常不错的。球队目前已经取得19胜11负的战绩,排在积分榜第7位,冲击季后赛形势一片大好。如果琼斯和霍尔曼两大王牌外援能够回归的话,吉林队晋级季后赛的可能性非常大,他们甚至有望成为季后赛的黑马。

而在希尔加盟以后,吉林队的季后赛前景则难以预料。毕竟,希尔的真正实力究竟如何,这恐怕还需要联赛的检验。其次,一旦希尔出战的话,这也就意味着,吉林队不再是全华班出战,选择单外援出战,在规则上是不利于他们的,这样一来,他们真的有胜算吗?返回搜狐,查看更多

责任编辑:


索帅称曼联以退为进改善文化,向博格巴提一要求!钦点一人做队长_索尔斯克亚

索帅称曼联以退为进改善文化,向博格巴提一要求!钦点一人做队长_索尔斯克亚


原标题:索帅称曼联以退为进改善文化,向博格巴提一要求!钦点一人做队长

英超重启后,曼联马上将恶战连场,周五做客热刺,下周三主场对谢菲联,周末则在客场与诺维奇争夺足总杯四强名额。不过,在面对穆里尼奥的球队前,索尔斯克亚的言论隐约带有暗示意味,他坚称球队已经准备好接受挑战,而且俱乐部文化已经比穆帅时代明显改善。

红魔主帅对英超能够重启表示兴奋:「我们已经做好了充分的准备。这感觉就像一个新赛季,每个赛季开始前你总是有些兴奋,但你的内心有蝴蝶飞舞,因为你想测试自己现在处于什么水平。我们已准备就绪,在停摆期间,体能教练与小伙子们保持联系,他们进行视频训练,现在球员们看上去精神焕发,身体也很好。我们需要打好开局,曼联将在一周内面临三场重要比赛,我们希望延续停摆前的势头。」

虽然曼联上赛季末本赛季初曾经历低迷,但索帅认为,这是「以退为进」。「我对球员的成长感到非常满意。我们的新援被证明是很好的收购,对于俱乐部来说,我们后退了一步,说我们需要改变文化,改变一些事情,我在俱乐部的支持下做出了这样的决定。」索尔斯克亚说,「对我来说,与这个教练组一起工作,是一个很好的环境。当你一直期待着回来与大家见面,这是一种很棒的感觉,这是我们迈出的第一步。我们需要营造这种环境,既具有挑战性,也能帮助球员发展。」

但索尔斯克亚也提醒曼联弟子,必须用成绩证明自己。「显然,现在球队来到了关键时期。剩下9场比赛,这是一个小型赛季。但是我们必须追赶失地,因为曼联开局丢失了太多积分。所以这是我们面临的挑战,孩子们必须有所表现。」

展开全文

曼联青训妖星拉什福德最近在球场外的慈善行为备受好评,索尔斯克亚也用他作为曼联文化改造成功的例子。「以他的出身,能够做出这样的贡献,对他来说意义比进球更大,因为这改变了人们的生活。」索帅表示。

拉什福德不仅自己出钱出力筹款2000万镑为英国儿童提供免费餐饮,上周也通过自己的影响力,令英国首相改变政策,拨款1.2亿给学生供应免费的夏季饮食。

索尔斯克亚认为,拉什福德完全能够成为未来的曼联队长。「他是出色的年轻人,我们为他自豪,我相信他的家人也相当骄傲。他表现出强大的人际交往能力、领袖技能和素质。他在联赛杯半决赛对阵曼城的比赛中,就担任过曼联队长。我们希望帮助他成熟,充分展现他的潜力。」

在球场上,22岁的拉什福德各项赛事攻入19球,创造职业生涯新高。联赛暂停,给了他养好背伤重返球场的机会,索帅披露:「他的情况很好,渴望回到球场踢球,就跟他为孩子争取免费食物一样。」

「他正在走向成熟,他越来越习惯于左内锋位置。我认为,作为右脚前锋,这永远是一个不错的位置。而在中路,他也可以担任双前锋之一,那就是马库斯的漂亮之处,他能踢很多位置。不过,这个赛季他一直在左路,我觉得他的成长了很多。他的决策日趋成熟,他的跑位非常出色,而且他的身体总是对任何对手构成挑战。他总是有沉着冷静的态度,像对阵巴黎圣日耳曼时主罚点球,那是他第一次在一队踢点球。但他的表现,让你看到一个在场上充满信心的孩子。」

除了拉什福德,博格巴也将为曼联伤愈复出迎战热刺,索尔斯克亚向他提出一个要求:像2018年俄罗斯世界杯代表法国队那样,成为球队的领袖。

「保罗(博格巴)经历了一个艰难的赛季,但他最近很兴奋,跃跃欲试。」索尔斯克亚说,「他努力训练,情绪很好,现在已经准备向前再进一步。我们在训练课和对西布朗的热身赛中,已经初步看过他跟布鲁诺(费尔南德斯)的搭档,好球员始终可以一起踢球。保罗现在的首要目的是找到自己的节奏,恢复比赛状态。我认为,你不能指望保罗和马库斯上来状态就起飞,我们必须接受他们可能经历几场比赛,才能真正恢复自我。但是我对此很耐心,让他得到更多的比赛时间,确保他的身体健康,并恢复到100%的水平。」

但博格巴最近在场外又出了麻烦,他的劳斯莱斯豪车因为使用外国车牌,被英国警方拖走。索帅希望他能把注意力集中在球场上:「保罗是世界杯冠军,我们希望他能展现出那种领袖能力。他是世界上最好的球员之一,希望我们尽快可能让他发挥实力。他因为伤病遇到困难,但我现在可以看出,他的精神和专注都很好,他恢复健康参与训练,准备好证明自己一直都有实力。我对保罗的要求,跟对其他队员一样:那就是你要拼尽全力做到最好。」

对于曼联中场如何用人,索尔斯克亚解释说:「这给我带来的不是问题,而是一大挑战,我需要选择合适的球员。内马尼亚(马蒂奇)、斯科特(麦克托米内)和弗雷德都表现很强,布鲁诺也带来巨大影响。保罗复出,只会给我们更多帮助,因为他拥有其他人没有的实力。」返回搜狐,查看更多

责任编辑:


亚马逊让关键词上首页需要注意什么?

亚马逊让关键词上首页需要注意什么?

关键词如果排在首页的话可以得到更多的流量及销量,但是想要让关键词上首页也是比较难的,那么首先我们需要了解一下亚马逊想让关键词上首页需要注意什么?

4201.png

产品权重=转化率+预期转化率+退货率+Review评级

A. 产品权重部分

1、 转化率

根据亚马逊最新A9算法来看的话,一个产品流量不一定需要特别大,但是转化率一定要高。如果我们产品的转化率高,亚马逊会认为我们的listing在各个方面都做的比较不错。这样子的话,流量的效果会最大化的体现出来。因为亚马逊的流量也不是白捡来的,他们也是通过各种付费或者免费的站外推广,从而获得的这些流量。所以说,流量都是需要成本的,那么自然而然,转化率就成了亚马逊对我们listing的一个重要考量标准之一。

2、预期转化率

什么叫做预期转化率呢?

比如我们现在这个新产品listing在10月4号的转化率在10%,10月5号达到12%,10月6号达到13%,以此类推。那么亚马逊系统也会给我们的listing一个预期判定,大概多少时间内转化率会上升到多少指标,然后会给到我们更多的流量。当然,亚马逊也是希望他的流量利用率能够达到最大化。

4202.png

3、退货率

如果说我们的产品销量特别不错,但是退货率比较高,我们listing的权重一样会被下拉下来。

4、Review评级

这个作用主要是给顾客作为一个参考来看的,对产品权重来说影响比较低,但是对于我们产品转化率来说,却比较重要。

店铺权重=店铺的Feedback等健康度指标

比如,退款退货频率,迟发率,feedback评级等

综上所述呢,我们可以看到影响排名最重要因素就是转化率和预期转化率,因此如果只是关键词上到首页还是不够的,我们还需要优化好我们的listing页面,这样才能保住我们关键词在首页的位置。

4203.png



文章来源:https://www.ikjzd.com/home/124036,更多跨境电商运营技巧:https://www.ikjzd.com

2020年6月19日星期五

价之链未完成业绩承诺,需赔偿10亿巨款!

价之链未完成业绩承诺,需赔偿10亿巨款!


由于价之链没有完成《盈利补偿协议》约定的2017-2019年累计实现5.1亿元净利润的业绩承诺,已经触发业绩补偿的相关约定。补偿义务人价之链应在2020年5月18日前,以现金方式向公司支付业绩补偿。

根据《盈利补偿协议》的约定,价之链需以现金方式向浔兴股份支付业绩承诺补偿金额与减值测试补偿金额,两项合计10亿1399万元。

浔兴股份表示,截至目前,价之链仍未向公司支付补偿款。按照相关规定,从2020年5月29日起,补偿义务人应按照未付款金额每日万分之三向公司支付逾期付款利息。


Centos8 安装docker

在安装docker时候遇到很多问题,在这里分享一下,

1.在国内使用docker官方的源真的是慢,

https://download.docker.com/linux/centos/#Docker官方源

[root@localhost ~]# cat /etc/yum.repos.d/Docker-ce.repo

[docker-ce-stable]name=Docker CE Stable - $basearchbaseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/7/$basearch/stableenabled=1gpgcheck=1gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg我这里用的阿里云的源2.手动安装 container.ioyum install -y https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/edge/Packages/containerd.io-1.2.6-3.3.el7.x86_64.rpm 3.安装Docker install -y docker-ce启动Docker#systemctl start docker4.验证 

 

5.pull镜像

#docker search  镜像名字 //搜索镜像

#docker pull ubuntu  //从仓库下载镜像

你会发现pull非常慢 

 

 解决

使用docker镜像加速

参考https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors?accounttraceid=b05fd04232be4d4388b3da5bae1ab089aque

 

 

# mkdir -p /etc/docker
# tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://p8sswz3o.mirror.aliyuncs.com"]
}
EOF
#systemctl daemon-reload
# systemctl restart docker

 

 

 

4.安装docker-ce出错

 .

 

手动安装containerd.io

yum install -y https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/edge/Packages/containerd.io-1.2.6-3.3.el7.x86_64.rpm

在安装docker-ce

yum install -y docker-ce

解决

 

 

 

 

     

 

Centos8 安装docker

认证授权方案之JwtBearer认证

1.前言

回顾:认证方案之初步认识JWT

在现代Web应用程序中,即分为前端与后端两大部分。当前前后端的趋势日益剧增,前端设备(手机、平板、电脑、及其他设备)层出不穷。因此,为了方便满足前端设备与后端进行通讯,就必须有一种统一的机制。所以导致API架构的流行。而RESTful API这个API设计思想理论也就成为目前互联网应用程序比较欢迎的一套方式。

这种API架构思想的引入,因此,我们就需要考虑用一种标准的,通用的,无状态的,与语言无关的身份认证方式来实现API接口的认证。

HTTP提供了一套标准的身份验证框架:服务端可以用来针对客户端的请求发送质询(challenge),客户端根据质询提供应答身份验证凭证。

质询与应答的工作流程如下:服务端向客户端返回401(Unauthorized,未授权)状态码,并在WWW-Authenticate头中添加如何进行验证的信息,其中至少包含有一种质询方式。然后客户端可以在请求中添加Authorization头进行验证,其Value为身份验证的凭证信息。

在本文中,将要介绍的是以Jwt Bearer方式进行认证。
JwtBearer

2.Bearer认证

本文要介绍的Bearer验证也属于HTTP协议标准验证,它随着OAuth协议而开始流行,详细定义见: RFC 6570。

  +--------+        +---------------+  |  |--(A)- Authorization Request ->| Resource |  |  |        |  Owner  |  |  |<-(B)-- Authorization Grant ---|    |  |  |        +---------------+  |  |  |  |        +---------------+  |  |--(C)-- Authorization Grant -->| Authorization |  | Client |        |  Server |  |  |<-(D)----- Access Token -------|    |  |  |        +---------------+  |  |  |  |        +---------------+  |  |--(E)----- Access Token ------>| Resource |  |  |        |  Server |  |  |<-(F)--- Protected Resource ---|    |  +--------+        +---------------+

A security token with the property that any party in possession of the token (a "bearer") can use the token in any way that any other party in possession of it can. Using a bearer token does not require a bearer to prove possession of cryptographic key material (proof-of-possession).

因此Bearer认证的核心是Token,Bearer验证中的凭证称为BEARER_TOKEN,或者是access_token,它的颁发和验证完全由我们自己的应用程序来控制,而不依赖于系统和Web服务器,Bearer验证的标准请求方式如下:

Authorization: Bearer [BEARER_TOKEN] 

那么使用Bearer验证有什么好处呢?

  • CORS: cookies + CORS 并不能跨不同的域名。而Bearer验证在任何域名下都可以使用HTTP header头部来传输用户信息。
  • 对移动端友好: 当你在一个原生平台(iOS, Android, WindowsPhone等)时,使用Cookie验证并不是一个好主意,因为你得和Cookie容器打交道,而使用Bearer验证则简单的多。
  • CSRF: 因为Bearer验证不再依赖于cookies, 也就避免了跨站请求攻击。
  • 标准:在Cookie认证中,用户未登录时,返回一个302到登录页面,这在非浏览器情况下很难处理,而Bearer验证则返回的是标准的401 challenge

3.JWT

上面介绍的Bearer认证,其核心便是BEARER_TOKEN,那么,如何确保Token的安全是重中之重。一种是通过HTTPS的方式,另一种是通过对Token进行加密编码签名,而最流行的Token编码签名方式便是:JSON WEB TOKEN。

Json web token (Jwt), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准(RFC 7519)。该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

JWT是由.分割的如下三部分组成:

Header.Payload.Signature

JwtBearer

还记得之前说个的一篇认证方案之初步认识JWT吗?没有的,可以看看,对JWT的特点和基本原理介绍,可以进一步的了解。

学习了之前的文章后,我们可以发现使用JWT的好处在于通用性、紧凑性和可拓展性。

  • 通用性:因为json的通用性,所以JWT是可以进行跨语言支持的,像JAVA,JavaScript,NodeJS,PHP等很多语言都可以使用。
  • 紧凑性:JWT的构成非常简单,字节占用很小,通过 GET、POST 等放在 HTTP 的 header 中,便于传输。
  • 可扩展性:JWT是自我包涵的,因为有了payload部分,包含了必要的一些其他业务逻辑所必要的非敏感信息,自身存储,不需要在服务端保存会话信息, 非常易于应用的扩展。

4.开始

1. 注册认证服务

在这里,我们用微软给我们提供的JwtBearer认证方式,实现认证服务注册 。

引入nuget包:Microsoft.AspNetCore.Authentication.JwtBearer

注册服务,将服务添加到容器中,

 public void ConfigureServices(IServiceCollection services) {  services.AddControllers();  var Issurer = "JWTBearer.Auth"; //发行人  var Audience = "api.auth";  //受众人  var secretCredentials = "q2xiARx$4x3TKqBJ"; //密钥  //配置认证服务  services.AddAuthentication(x =>  {   x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;   x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;  }).AddJwtBearer(o=>{   o.TokenValidationParameters = new TokenValidationParameters   {    //是否验证发行人    ValidateIssuer = true,    ValidIssuer = Issurer,//发行人    //是否验证受众人    ValidateAudience = true,    ValidAudience = Audience,//受众人    //是否验证密钥    ValidateIssuerSigningKey = true,    IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretCredentials)),        ValidateLifetime = true, //验证生命周期    RequireExpirationTime = true, //过期时间   };  }); }

注意说明:

一. TokenValidationParameters的参数默认值:1. ValidateAudience = true, ----- 如果设置为false,则不验证Audience受众人2. ValidateIssuer = true , ----- 如果设置为false,则不验证Issuer发布人,但建议不建议这样设置3. ValidateIssuerSigningKey = false,4. ValidateLifetime = true, ----- 是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比5. RequireExpirationTime = true, ----- 是否要求Token的Claims中必须包含Expires6. ClockSkew = TimeSpan.FromSeconds(300), ----- 允许服务器时间偏移量300秒,即我们配置的过期时间加上这个允许偏移的时间值,才是真正过期的时间(过期时间 +偏移值)你也可以设置为0,ClockSkew = TimeSpan.Zero

调用方法,配置Http请求管道:

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {  if (env.IsDevelopment())  {   app.UseDeveloperExceptionPage();  }  app.UseRouting();  //1.先开启认证  app.UseAuthentication();  //2.再开启授权  app.UseAuthorization();  app.UseEndpoints(endpoints =>  {   endpoints.MapControllers();  }); }

JwtBearerOptions的配置中,通常IssuerSigningKey(签名秘钥), ValidIssuer(Token颁发机构), ValidAudience(颁发给谁) 三个参数是必须的,后两者用于与TokenClaims中的IssuerAudience进行对比,不一致则验证失败。

2.接口资源保护

创建一个需要授权保护的资源控制器,这里我们用建立API生成项目自带的控制器,WeatherForecastController.cs, 在控制器上使用Authorize即可

[ApiController][Route("[controller]")][Authorize]public class WeatherForecastController : ControllerBase{ private static readonly string[] Summaries = new[] {  "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; private readonly ILogger<WeatherForecastController> _logger; public WeatherForecastController(ILogger<WeatherForecastController> logger) {  _logger = logger; } [HttpGet] public IEnumerable<WeatherForecast> Get() {  var rng = new Random();  return Enumerable.Range(1, 5).Select(index => new WeatherForecast  {   Date = DateTime.Now.AddDays(index),   TemperatureC = rng.Next(-20, 55),   Summary = Summaries[rng.Next(Summaries.Length)]  })  .ToArray(); }}

3. 生成Token

因为微软为我们内置了JwtBearer验证,但是没有提供Token的发放,所以这里我们要实现生成Token的方法

引入Nugets包:System.IdentityModel.Tokens.Jwt

这里我们根据IdentityModel.Tokens.Jwt文档给我们提供的帮助类,提供了方法WriteToken创建Token,根据参数SecurityToken,可以实例化,JwtSecurityToken,指定可选参数的类。

  /// <summary>  /// Initializes a new instance of the <see cref="JwtSecurityToken"/> class specifying optional parameters.  /// </summary>  /// <param name="issuer">If this value is not null, a { iss, 'issuer' } claim will be added, overwriting any 'iss' claim in 'claims' if present.</param>  /// <param name="audience">If this value is not null, a { aud, 'audience' } claim will be added, appending to any 'aud' claims in 'claims' if present.</param>  /// <param name="claims">If this value is not null then for each <see cref="Claim"/> a { 'Claim.Type', 'Claim.Value' } is added. If duplicate claims are found then a { 'Claim.Type', List&lt;object&gt; } will be created to contain the duplicate values.</param>  /// <param name="expires">If expires.HasValue a { exp, 'value' } claim is added, overwriting any 'exp' claim in 'claims' if present.</param>  /// <param name="notBefore">If notbefore.HasValue a { nbf, 'value' } claim is added, overwriting any 'nbf' claim in 'claims' if present.</param>  /// <param name="signingCredentials">The <see cref="SigningCredentials"/> that will be used to sign the <see cref="JwtSecurityToken"/>. See <see cref="JwtHeader(SigningCredentials)"/> for details pertaining to the Header Parameter(s).</param>  /// <exception cref="ArgumentException">If 'expires' &lt;= 'notbefore'.</exception>  public JwtSecurityToken(string issuer = null, string audience = null, IEnumerable<Claim> claims = null, DateTime? notBefore = null, DateTime? expires = null, SigningCredentials signingCredentials = null)  {   if (expires.HasValue && notBefore.HasValue)   {    if (notBefore >= expires)     throw LogHelper.LogExceptionMessage(new ArgumentException(LogHelper.FormatInvariant(LogMessages.IDX12401, expires.Value, notBefore.Value)));   }   Payload = new JwtPayload(issuer, audience, claims, notBefore, expires);   Header = new JwtHeader(signingCredentials);   RawSignature = string.Empty;  }

这样,我们可以根据参数指定内容:

1. string iss = "JWTBearer.Auth"; // 定义发行人2. string aud = "api.auth";  //定义受众人audience3. IEnumerable<Claim> claims = new Claim[]{new Claim(JwtClaimTypes.Id,"1"),new Claim(JwtClaimTypes.Name,"i3yuan"),};//定义许多种的声明Claim,信息存储部分,Claims的实体一般包含用户和一些元数据4. var nbf = DateTime.UtcNow; //notBefore 生效时间5. var Exp = DateTime.UtcNow.AddSeconds(1000); //expires 过期时间6. string sign = "q2xiARx$4x3TKqBJ"; //SecurityKey 的长度必须 大于等于 16个字符 var secret = Encoding.UTF8.GetBytes(sign); var key = new SymmetricSecurityKey(secret); var signcreds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

好了,通过以上填充参数内容,进行传参赋值得到,完整代码如下:

新增AuthController.cs控制器:

 [HttpGet] public IActionResult GetToken() {  try  {   //定义发行人issuer   string iss = "JWTBearer.Auth";   //定义受众人audience   string aud = "api.auth";   //定义许多种的声明Claim,信息存储部分,Claims的实体一般包含用户和一些元数据   IEnumerable<Claim> claims = new Claim[]   {    new Claim(JwtClaimTypes.Id,"1"),    new Claim(JwtClaimTypes.Name,"i3yuan"),   };   //notBefore 生效时间   // long nbf =new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds();   var nbf = DateTime.UtcNow;   //expires //过期时间   // long Exp = new DateTimeOffset(DateTime.Now.AddSeconds(1000)).ToUnixTimeSeconds();   var Exp = DateTime.UtcNow.AddSeconds(1000);   //signingCredentials 签名凭证   string sign = "q2xiARx$4x3TKqBJ"; //SecurityKey 的长度必须 大于等于 16个字符   var secret = Encoding.UTF8.GetBytes(sign);   var key = new SymmetricSecurityKey(secret);   var signcreds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);   var jwt = new JwtSecurityToken(issuer: iss, audience: aud, claims:claims,notBefore:nbf,expires:Exp, signingCredentials: signcreds);		 var JwtHander = new JwtSecurityTokenHandler();   var token = JwtHander.WriteToken(jwt);   return Ok(new   {    access_token = token,    token_type = "Bearer",   });  }  catch (Exception ex)  {   throw;  } }
注意:1.SecurityKey 的长度必须 大于等于 16个字符,否则生成会报错。(可通过在线随机生成密钥)

5. 运行

访问获取Token方法,获取得到access_token:

JwtBearer

再访问,授权资源接口,可以发现,再没有添加请求头token值的情况下,返回了401没有权限。

JwtBearer

这次,在请求头通过Authorization加上之前获取的token值后,再次进行访问,发现已经可以获取访问资源控制器,并返回对应的数据。

JwtBearer

6.扩展说明

在HTTP标准验证方案中,我们比较熟悉的是"Basic"和"Digest",前者将用户名密码使用BASE64编码后作为验证凭证,后者是Basic的升级版,更加安全,因为Basic是明文传输密码信息,而Digest是加密后传输。

一、Basic基础认证

Basic认证是一种较为简单的HTTP认证方式,客户端通过明文(Base64编码格式)传输用户名和密码到服务端进行认证,通常需要配合HTTPS来保证信息传输的安全。

客户端请求需要带Authorization请求头,值为"Basic xxx",xxx为"用户名:密码"进行Base64编码后生成的值。 若客户端是浏览器,则浏览器会提供一个输入用户名和密码的对话框,用户输入用户名和密码后,浏览器会保存用户名和密码,用于构造Authorization值。当关闭浏览器后,用户名和密码将不再保存。

凭证为"YWxhzGRpbjpvcGVuc2VzYWl1",是通过将"用户名:密码"格式的字符串经过的Base64编码得到的。而Base64不属于加密范畴,可以被逆向解码,等同于明文,因此Basic传输认证信息是不安全的。

Basic基础认证图示:

JwtBearer

缺陷汇总
1.用户名和密码明文(Base64)传输,需要配合HTTPS来保证信息传输的安全。
2.即使密码被强加密,第三方仍可通过加密后的用户名和密码进行重放攻击。
3.没有提供任何针对代理和中间节点的防护措施。
4.假冒服务器很容易骗过认证,诱导用户输入用户名和密码。

二、Digest摘要认证

Digest认证是为了修复基本认证协议的严重缺陷而设计的,秉承"绝不通过明文在网络发送密码"的原则,通过"密码摘要"进行认证,大大提高了安全性。

Digest认证步骤如下:
第一步:客户端访问Http资源服务器。由于需要Digest认证,服务器返回了两个重要字段nonce(随机数)和realm。
第二步:客户端构造Authorization请求头,值包含username、realm、nouce、uri和response的字段信息。其中,realm和nouce就是第一步返回的值。nouce只能被服务端使用一次。uri(digest-uri)即Request-URI的值,但考虑到经代理转发后Request-URI的值可能被修改、因此实现会复制一份副本保存在uri内。response也可叫做Request-digest,存放经过MD5运算后的密码字符串,形成响应码。
第三步:服务器验证包含Authorization值的请求,若验证通过则可访问资源。
Digest认证可以防止密码泄露和请求重放,但没办法防假冒。所以安全级别较低。
Digest和Basic认证一样,每次都会发送Authorization请求头,也就相当于重新构造此值。所以两者易用性都较差。

Digest认证图示:
JwtBearer

7.注意

  1. 在进行JwtBearer认证时,在生成token之后,还需要与刷新token配合使用,因为当用户执行了退出,修改密码等操作时,需要让该token无效,无法再次使用,所以,会给access_token设置一个较短的有效期间,(JwtBearer认证默认会验证有效期,通过notBeforeexpires来验证),当access_token过期后,可以在用户无感知的情况下,使用refresh_token重新获取access_token,但这就不属于Bearer认证的范畴了,但是我们可以通过另一种方式通过IdentityServer的方式来实现,在后续中会对IdentityServer进行详细讲解。
  2. 在生成token的时候,需要用的secret,主要是用来防止token被伪造与篡改。因为当token被劫取的时候,可以得到你的令牌中带的一些个人不重要的信息明文,但不用担心,只要你不在生成token里把私密的个人信息放出去的话,就算被动机不良的人得到,也做不了什么事情。但是你可能会想,如果用户自己随便的生成一个 token ,带上你的信息,那不就可以随便访问你的资源服务器了,因此这个时候就需要利用secret 来生成 token,来确保数字签名的正确性。而且在认证授权资源,进行token解析的时候,通过微软的源码发现,已经帮我们封装了方法,对secret进行了校验了,确保了token的安全性,从而保证api资源的安全。

8.总结

  1. JwtToken在认证时,无需Security token service安全令牌服务器的参与,都是基于Claim的,默认会验证有效期,通过notBeforeexpires来验证,这在分布式中提供给了极大便利。
  2. JwtToken与平台、无言无关,在前端也可以直接解析出Claims。
  3. 如果有不对的或不理解的地方,希望大家可以多多指正,提出问题,一起讨论,不断学习,共同进步。
  4. 后面会对认证授权方案中的授权这一块进行说明分享。
  5. 本示例源码地址
    参考JwtBearer源码
认证授权方案之JwtBearer认证

使用cmd命令行(.NET Core CLI)来启动ASP.NET Core 应用程序的多个实例

本章主要和大家分享下如何使用cmd命令行(.NET Core CLI)来启动ASP.NET Core 应用程序的多个实例,以此来模拟集群。

本章主要和大家分享下如何使用cmd命令行(.NET Core CLI)来启动ASP.NET Core 应用程序的多个实例,以此来模拟集群。

.NET Core 命令行接口 (CLI) 工具是用于开发、生成、运行和发布 .NET Core 应用程序的跨平台工具链。

CLI 命令结构包含驱动程序(“dotnet”)和命令,还可能包含命令参数和选项。

话不多说,下面我们进入本章主题:

首先我们来建个MVC的项目(目标框架:.NET Core 3.1),如下所示:

进入项目文件.csproj所在的目录

输入cmd后按Enter键就可以快速进入到指定目录

dotnet run //.NET Core CLI命令 无需任何显式编译或启动命令即可运行源代码。

这样子就算是启动成功了,使用dotnet run命令启动默认端口号是launchSettings.json中设置的5000

我们使用5000端口在浏览器中访问看下是否真的启动成功了

可以看到确实是启动成功了

此时我们可以按Ctrl + C来停止程序,停止成功如下所示:

此时你如果不想使用5000端口,可以使用--urls命令参数来指定具体的端口,例如:

dotnet run --urls=http://*:8080

同样的操作可以多开几个命令行窗口,这样子就可以做到同一套代码,启动不同进程,监听不同端口,以此来模拟集群了,如下所示。

上面我们开了2个cmd界面,分别启动了一个实例,端口号分别为8080和8081,下面我们就可以使用这2个端口号访问了

可以发现我们用这2个端口号都访问成功了

此外还可以运行指定的项目

dotnet run -p NETCoreCLI.csproj //一个“-”是简称的pdotnet run --project NETCoreCLI.csproj //两个“-”是全称的project

此处输入NETCoreCLI.csproj有个小技巧,就是输入一个N后按Tab键就会自动补齐,这样子就不用一个个字输入了。

PS:需要特别注意的是上面介绍的启动方式,一旦修改了程序代码则都需要使用Ctrl+C停止后重新启动。

当然有个小技巧就是加watch自动监听程序代码的修改,一旦修改了代码就会自动重启。

dotnet watch run -p NETCoreCLI.csproj --urls=http://*:8080

此外还有一个命令主要是用来启动发布后的应用,如下所示:

PS:使用该命令启动的方式,一旦修改了代码就需要停止,然后重新生成发布,最后重新启动。

dotnet [解决方案bin文件下的dll文件] --urls=http://*:8080dotnet NETCoreCLI.dll --urls=http://*:8080

如果使用该命令直接启动没有发布的应用则可能有些资源文件就访问不到了,如下:

此时虽然可以启动成功但是有些资源访问不到,如下所示:

故该命令主要是用来启动发布后的应用,如下所示:

首先我们将项目发布下,点击项目 => 右键 => 选择发布

选择IIS、FTP等

选择文件系统

然后进行发布

最后使用命令启动发布后的应用

可以看到启动成功了

本文涉及到的.NET Core CLI命令小结

dotnet rundotnet run --urls=http://*:8080 //urls指定ip和端口dotnet watch run //watch监听程序修改,一旦修改则重新启动dotnet watch run --urls=http://*:8080dotnet run -p NETCoreCLI.csproj //一个“-”是简称的pdotnet run --project NETCoreCLI.csproj //两个“-”是全称的projectdotnet watch run -p NETCoreCLI.csproj --urls=http://*:8080dotnet [解决方案bin文件下的dll文件] --urls=http://*:8080dotnet NETCoreCLI.dll --urls=http://*:8080dotnet clean //清除项目的默认生成,与VS中的右键清理效果是一样的Ctrl + C //停止cls //清除屏幕Tab键 //自动补齐

PS:

详细的.NET Core CLI可参考官网:https://docs.microsoft.com/zh-cn/dotnet/core/tools/dotnet-run

 

此文由博主精心撰写转载请保留此原文链接:https://www.cnblogs.com/xyh9039/p/13155059.html

版权声明:如有雷同纯属巧合,如有侵权请及时联系本人修改,谢谢!!!

使用cmd命令行(.NET Core CLI)来启动ASP.NET Core 应用程序的多个实例

002.OpenShift安装与部署

一 前置条件说明

1.1 安装准备概述

Red Hat OpenShift容器平台是由Red Hat作为RPM包和容器映像两种类型存在。RPM包使用订阅管理器从标准Red Hat存储库(即Yum存储库)下载,容器映像来自Red Hat私有仓库。OpenShift容器平台安装需要多个服务器,支持服务器或虚拟机的多种形式。同时为了简化OpenShift集群的部署,Red Hat提供了一个基于Ansible的安装程序,它可以通过交互运行,也可以使用包含环境配置细节的应答文件以自动的非交互方式运行。在运行安装程序之前,需要执行一些预安装任务,以及安装后的安装任务,以获得功能齐全的OpenShift容器平台集群。RedHat为安装OpenShift容器平台提供了两种不同的方法。
  • 第一种方法使用快速安装程序,可用于简单的集群设置。
  • 第二种方法是较为精细的安装方式,并使用Ansible playbook来自动化该过程。
本实验使用Ansible来自动配置OpenShift集群。同时,Ansible可以为OpenShift安装准备主机,例如包安装、禁用服务和客户化配置。提示:更多Ansible内容参考https://www.cnblogs.com/itzgr/category/1333622.html

1.2 节点准备

需要相应的master和node节点互通,并且配置master至所有节点的免秘钥登录。同时能解析所有FQDN,及注册相应repo库。提示:以上准备工作也可通过Ansible直接跑相应的yml完成。

二 实验一:前置条件操作

2.1 环境准备

[student@workstation ~]$ lab install-prepare setup #运行准备脚本提示:本环境基于RedHat RH280环境,所有lab命令为环境自动化准备命令,后续不再赘述。

2.2 安装Ansible

[student@workstation ~]$ rpm -qa | grep ansible[student@workstation ~]$ sudo yum -y install ansible

2.3 验证Ansible

[student@workstation ~]$ cd /home/student/DO280/labs/install-prepare/[student@workstation ~]$ ansible --version[student@workstation install-prepare]$ cat ansible.cfgclipboard[student@workstation install-prepare]$ cat inventoryclipboardInventory文件解释:Inventory定义了六个主机组:
  • workstations:为developer节点,即运行playbook的节点;
  • nfs:为集群存储提供nfs服务的环境中的vm;
  • masters:OpenShift集群中用作master角色的节点;
  • etcd:用于OpenShift集群的etcd服务的节点,本环境中使用master节点;
  • node:OpenShift集群中的node节点;
  • OSEv3:组成OpenShift集群的所有接待,包括master、etcd、node或nfs组中的节点。
注意:默认情况下,docker使用在线仓库下载容器映像。本环境内部无网络,因此将docker仓库配置为内部私有仓库。在yml中使用变量引入仓库配置。此外,安装会在每个主机上配置docker守护进程,以使用overlay2 image驱动程序存储容器映像。Docker支持许多不同的image驱动。如AUFS、Btrfs、Device mapper、OverlayFS。

2.4 检查节点连通性

[student@workstation install-prepare]$ cat ping.yml
 1 --- 2 - name: Verify Connectivity 3 hosts: all 4 gather_facts: no 5 tasks: 6  - name: "Test connectivity to machines." 7  shell: "whoami" 8  changed_when: false
[student@workstation install-prepare]$ ansible-playbook -v ping.yml

2.5 确认yml

[student@workstation install-prepare]$ cat prepare_install.yml clipboard解释:如上yml引入了三个role。docker-storage内容如下,该role定义相关docker的后端存储驱动以及创建docker所需的image存储路径,并最终启动docker。[student@workstation install-prepare]$ cat roles/docker-storage/tasks/main.yml
 1 --- 2 - block: 3 - name: Customize default /etc/sysconfig/docker-storage-setup 4  template: 5  src: docker-storage-setup 6  dest: /etc/sysconfig/docker-storage-setup 7  owner: root 8  group: root 9  mode: 0644 10  when: not use_overlay2_driver 11 - name: Customize /etc/sysconfig/docker-storage-setup using overlay2 storage driver 12  template: 13  src: docker-storage-setup-overlay2 14  dest: /etc/sysconfig/docker-storage-setup 15  owner: root 16  group: root 17  mode: 0644 18  when: use_overlay2_driver 19 - name: Verify existence of /dev/docker-vg/docker-pool 20  stat: 21  path: /dev/docker-vg/docker-pool 22  register: p 23 - name: Stop docker 24  service: 25  name: docker 26  state: stopped 27  when: p.stat.exists == False 28 - name: Remove loopback docker files 29  file: 30  dest: /var/lib/docker 31  state: absent 32  when: p.stat.exists == False 33 - name: Run docker-storage-setup 34  command: /usr/bin/docker-storage-setup 35  when: p.stat.exists == False 36 - name: Start and enable docker 37  service: 38  name: docker 39  state: started 40  when: p.stat.exists == False 41 when: docker_storage_device is defined 42 
[student@workstation install-prepare]$ cat roles/docker-storage/templates/docker-storage-setup
 1 DEVS={{ docker_storage_device }} 2 VG=docker-vg 3 SETUP_LVM_THIN_POOL=yes
docker-registry-cert内容如下,该role定义相关docker的使用私有仓库,并且导入了相关crt证书。
[student@workstation install-prepare]$ cat roles/docker-registry-cert/tasks/main.yml
 1 --- 2 - name: Enable the Trust 3 shell: update-ca-trust enable 4 - name: Retrieve the certificate 5 fetch: 6  src: "{{ cacert }}" 7  dest: "{{ local_destination }}" 8 delegate_to: "{{ registry_host }}" 9 - name: Copy the certificate 10 copy: 11  src: "{{ source }}" 12  dest: "{{ destination }}" 13  owner: root 14  group: root 15  mode: 0755 16 - name: Update the Trust 17 shell: update-ca-trust extract 18 - name: Restart Docker 19 service: 20  name: docker 21  state: restarted 22 
[student@workstation install-prepare]$ cat roles/docker-registry-cert/vars/main.yml 
 1 registry_host: services.lab.example.com 2 cacert: /etc/pki/tls/certs/example.com.crt 3 local_destination: /tmp/ 4 source: "/tmp/{{ ansible_fqdn }}/etc/pki/tls/certs/example.com.crt" 5 destination: /etc/pki/ca-trust/source/anchors/example.com.crt
openshift-node内容如下,该role定义相关安装OpenShift所需的所有依赖包任务。
[student@workstation install-prepare]$ ll roles/openshift-node/files/ total 4-rw-r--r--. 1 student student 389 Jul 19 2018 id_rsa.pub[student@workstation install-prepare]$ cat roles/openshift-node/meta/main.yml
 1 --- 2 dependencies: 3 - { role: docker }
[student@workstation install-prepare]$ cat roles/openshift-node/tasks/main.yml
 1 --- 2 - name: Deploy ssh key to root at all nodes 3 authorized_key: 4  user: root 5  key: "{{ item }}" 6 with_file: 7  - id_rsa.pub 8 - name: Install required packages 9 yum: 10  name: "{{ item }}" 11  state: latest 12 with_items: 13  - wget 14  - git 15  - net-tools 16  - bind-utils 17  - iptables-services 18  - bridge-utils 19  - bash-completion 20  - kexec-tools 21  - sos 22  - psacct 23  - atomic-openshift-clients 24  - atomic-openshift-utils 25  - atomic-openshift 26 

2.6 运行playbook

[student@workstation ~]$ cd /home/student/DO280/labs/install-prepare/[student@workstation install-prepare]$ ansible-playbook prepare_install.ymlclipboard提示:该准备工作将完成如下操作:
  • 在每个节点上安装并运行Docker;
  • 在每个节点上Docker使用一个逻辑卷存储;
  • 每个节点使用自签名证书信任私有Docker仓库;
  • 在每个节点上都会安装基本包。

2.7 确认验证

[student@workstation install-prepare]$ for vm in master node1 node2;do echo -e "\n$vm"ssh $vm sudo systemctl status docker | head -n3done #验证docker服务clipboard[student@workstation install-prepare]$ for vm in master node1 node2;do echo -e "\n$vm : lvs"ssh $vm sudo lvsecho -e "\n$vm : df -h"ssh $vm sudo df -h | grep vg-dockerdone #查看docker使用的lvmclipboard[student@workstation install-prepare]$ for vm in master node1 node2;do echo -e "\n$vm"ssh $vm docker pull rhel7:latestdone #测试pull imageclipboard[student@workstation install-prepare]$ for vm in master node1 node2; do echo -e "\n$vm"ssh $vm rpm -qa wget git net-tools bind-utils \yum-utils iptables-services bridge-utils bash-completion \kexec-tools sos psacct atomic-openshift-utilsdone #检查相关依赖包是否安装成功

三 正式安装说明

3.1 安装步骤

安装准备完成后正式安装包括四个步骤:
  • 编写一个目录文件来描述所需的集群特性和体系结构;
  • 执行prerequisites.yml的playbook;
  • 执行deploy_cluster,yml的playbook;
  • 验证安装。

3.2 安装和配置节点

OpenShift Inventory定义了以下主机组。master:对于OpenShift,这是必须的组,定义了OpenShift集群中哪些主机充当master节点;node:对于OpenShift,这是必须的组,它定义了OpenShift集群中哪些主机充当node节点;etcd:[master]部分中列出的所有主机也应属于etcd;nfs:这个组是可选的,应该只包含一个主机。如果Inventory文件中存在特定的变量,OpenShift playbook将在这台机器上安装并配置NFS;OSEv3:这个组包含任何属于OpenShift集群的机器。安装剧本引用这个组来运行在集群全范围内的任务。[student@workstation install-prepare]$ cat inventoryclipboard说明:
  • 安装所需版本的OpenShift容器平台;
  • 用户使用htpasswd身份验证对集群进行身份验证;
  • DNS条目apps.lab.example.com用作OpenShift应用程序的子域;
  • NFS存储用于OpenShift etcd服务和OpenShift 内部仓库;
  • classroom container registry用作仓库。
变量说明:OpenShift安装变量记录在Inventory的[OSEv3:vars]部分。安装变量用于配置多个OpenShift组件,例如:
  • 一个内部容器仓库;
  • Gluster、Ceph等以便于提供持久性存储;
  • 集群日志;
  • 自定义集群证书。

3.3 配置OpenShift版本

可通过在[OSEv3:vars]中指定如下配置确定OpenShift所安装的版本:openshift_deployment_type=openshift-enterpriseopenshift_release=v3.9指定OpenShift部署类型,可选值为openshift-enterprise和origin。openshift_image_tag=v3.9.14openshift_disable_check=disk_availability,docker_storage,memory_availability容器化的OpenShift服务使用带有"v3.9.14"标记的图像。这将阻止集群自动升级到更新的容器映像;对于非生产集群,可以禁用对系统需求的检查。

3.4 配置验证

OpenShift容器平台身份验证基于OAuth, OAuth提供了一个基于HTTP的APl,用于对交互式和非交互式客户端进行身份验证。OpenShift master运行一个OAuth服务器,OpenShift可以支持多种Provider,这些Provider可以与特定于组织的身份管理产品集成。支持的OpenShift身份验证的Provider:
  • HTTP Basic,外部单点登录(SSO)系统;
  • 使用GitHub和GitLab帐号;
  • OpenID连接,使用OpenID-compatible SSO和谷歌帐户;
  • OpenStack Keystone v3;
  • LDAP v3服务器。
OpenShift安装程序使用默认的安全方法,DenyAllPasswordIdentityProvider是缺省提供程序。使用此Provider,表示只有master主机上的root用户才能使用OpenShift客户端命令和API。

3.5 配置htpasswd验证

OpenShift HTPasswdPasswordIdentityProvider根据Apache HTTPD htpasswd程序生成的文件验证用户和密码。htpasswd程序将用户名和密码保存在纯文本文件中,每行一条记录,字段用冒号分隔。密码使用MD5散列。如果将此文件添加或删除用户,或更改用户密码,OpenShift OAuth服务器将自动重新读取该文件。要将OpenShift master配置使用HTPasswdPasswordIdentityProvider,需要配置openshift_master_identity_providers。
 1 openshift_master_identity_providers。 2 openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', 3 'challenge': 'true', 'kind': 'HTPasswdPasswordIdentityProvider',	#配置后端驱动 4 'filename': '/etc/origin/master/htpasswd'}]				#制定master主机上
也支持在配置文件中直接指定初始的用户名和密码。openshift_master_htpasswd_users="{'user1':'$apr1$.NHMsZYc$MdmfWN5DM3q280/W7c51c/','user2':'$apr1$.NHMsZYc$MdmfWN5DM3q280/W7c51c/'}"生产hash密码可参考如下:
 1 [student@workstation ~]$ htpasswd -nb admin redhat 2 [student@workstation ~]$ openssl passwd -apr1 redhat

3.6 网络要求

集群节点的通配符DNS条目允许任何新创建的路由自动路由到subdomain的集群。通配符DNS条目必须存在于唯一的子域中,例如apps.mycluster.com,并解析为主机名或集群节点的IP地址。inventory文件中通配符DNS条目是通过变量openshift_master_default_subdomain进行设置 。openshift_master_default_subdomain=apps.mycluster.com

3.7 master服务端口

主服务端口openshift_master_api_port变量定义主API的监听端口。缺省端口8443,当master使用SSL时,也可以使用443端口。从而在连接的时候省略端口号。master console端口由openshift_master_console_port变量的值设置,默认端口是8443。master console端口也可以设置为443,从而在连接的时候省略端口号。3.8 防火墙OpenShift节点上的默认防火墙服务是iptables。若要在所有节点上使用firewalld作为防火墙服务,需要将操作系统防火墙使用firewalld变量设置为true,即os_firewall_use_firewalld=true。

四 配置持久化存储

4.1 持久存储配置

默认情况下,容器数据是临时的,并且在容器被销毁时丢失。Kubernetes持久卷框架为容器请求和使用持久存储提供了一种机制。为了避免数据丢失,这些服务被配置为使用持久卷。OpenShift支持多个插件,使用各种存储技术创建持久卷。可以使用NFS、iSCSI、GlusterFS、Ceph或其他商业云存储。本环境中,OpenShift容器registry和OpenShift Ansible Broker服务被配置为使用NFS持久性存储。提示:生产环境默认OpenShift不支持NFS持久存储集群,要允许NFS在非生产集群上持久存储,需要配置openshift_enable_unsupported_configurations=true。

4.2 container仓库

要为OpenShift容器registry配置NFS持久性存储,请将以下内容添加到Inventory文件中:
 1 openshift_hosted_registry_storage_kind=nfs 2 openshift_hosted_registry_storage_nfs_directory=/exports 3 openshift_hosted_registry_storage_volume_name=registry 4 openshift_hosted_registry_storage_nfs_options='*(rw,root_squash)' 5 openshift_hosted_registry_storage_volume_size=40G 6 openshift_hosted_registry_storage_access_modes=['ReadWriteMany']

4.3 OpenShift Ansible Broker

OpenShift Ansible Broker(OAB)是一个容器化的OpenShift服务,部署自己的etcd服务。持久Etcd存储所需的配置与registry所需的配置类似。
 1 openshift_hosted_etcd_storage_kind=nfs 2 openshift_hosted_etcd_storage_nfs_directory=/exports 3 openshift_hosted_etcd_storage_volume_name=etcd-vol2 4 openshift_hosted_etcd_storage_nfs_options="*(rw,root_squash,sync,no_wdelay)" 5 openshift_hosted_etcd_storage_volume_size=1G 6 openshift_hosted_etcd_storage_access_modes=["ReadWriteOnce"] 7 openshift_hosted_etcd_storage_labels={'storage': 'etcd'}

五 OpenShift其他配置

5.1 配置离线本地registry

本环境OpenShift使用容器仓库为registry.lab.example.com,要将集群配置为从内部仓库pull image,需要在Inventory中进行如下配置:
 1 #Modifications Needed for a Disconnected Install 2 oreg_url=registry.lab.example.com/openshift3/ose-${component}:${version} 3 #可访问image仓库的位置,必须以ose-${component}:${version}结尾。 4 openshift_examples_modify_imagestreams=true 5 #OpenShift安装了用于部署示例应用程序的模板。这个变量指示playbook修改所有示例的IS,使其指向私有仓库,而不是registry.access.redhat.com。 6 openshift_docker_additional_registries=registry.lab.example.com 7 #此变量用于将本地可访问仓库添加到每个节点上的docker配置中。 8 openshift_docker_blocked_registries=registry.access.redhat.com,docker.io 9 #此变量用于在OpenShift节点上配置docker的blocked_registries。
 1 #Image Prefix Modifications 2 openshift_web_console_prefix=registry.lab.example.com/openshift3/oseopenshift_cockpit_deployer_prefix='registry.lab.example.com/openshift3/' 3 openshift_service_catalog_image_prefix=registry.lab.example.com/openshift3/osetemplate_service_broker_prefix=registry.lab.example.com/openshift3/oseansible_service_broker_image_prefix=registry.lab.example.com/openshift3/oseansible_service_broker_etcd_image_prefix=registry.lab.example.com/rhel7/
#通过在容器image名称前面加上registry.lab.example.com以确保OpenShift服务的容器image可以从私有内部仓库下载。

5.2 配置NODE labels

节点label是分配给每个节点的任意key/value描述。node label通常用于区分地理数据中心或标识节点上的可用资源的有意义的描述。应用程序可以在其deployment中根据node lables配置一个选择器。如果匹配到,应用程序的pod必须部署在其符合node labels的节点上。使用主机变量openshift_node_tags在Inventory文件中设置节点标签。
 1 [nodes] 2 ...output omitted... 3 nodeX.example.com openshift_node_labels="{'zone':'west', 'gpu':'true'}" 4 ...output omitted...
如上所示配置给nodeX.example.com配置两个labels,zone=west和gpu=true。OpenShift集群的一个常见架构是区分master、infrastructure node和compute node。在此架构中,infrastructure node承载OpenShift Pod的registry和路由器,而compute node承载来自用户项目的应用程序pod。master节点不承载应用程序或infrastructure pod。可使用 node label 来标识特定节点的角色,通常master node label 为 node-role.kubernetes.io/master=true,infrastructure node label 为 region=infra,compute node label 为 noderole.kubernetes.io/compute=true。
 1 [nodes] 2 master.lab.example.com 3 node1.lab.example.com openshift_node_labels="{'region':'infra'}" 4 node2.lab.example.com
提示:如果一个节点设计为同时承载infrastructure 和 application pods,则必须显式定义两个节点标签。[nodes]...nodeX.example.com openshift_node_labels="{'region':'infra', 'noderole.kubernetes.io/compute':'true'}"...

六 执行剧本

6.1 剧本说明

安装OpenShift需要执行prerequisites.yml 和deploy_cluster.yml,由 atomic-openshift-utils 软件包安装。首先执行 prequisites.yml playbook 检查所有主机能够满足OpenShift 的部署,同时尝试修改主机以满足部署需求。然后执行 doploy_cluster.yml playbook 开始正式集群部署

6.2 验证OpenShift

部署完成后,可访问:https://master.lab.example.com 进行验证。

七 正式安装OpenShift

7.1 前置准备

[student@workstation ~]$ lab install-prepare setup[student@workstation ~]$ sudo yum -y install ansible[student@workstation ~]$ cd /home/student/do280-ansible/[student@workstation do280-ansible]$ ansible-playbook playbooks/prepare_install.yml #设置相关环境[student@workstation do280-ansible]$ lab install-run setup[student@workstation do280-ansible]$ cd /home/student/DO280/labs/install-run/

7.2 安装atomic

[student@workstation install-run]$ sudo yum -y install atomic-openshift-utils提示:atomic-openshift-utils提供了安装OpenShift所需的Ansible playbook和role。

7.3 创建Inventory

[student@workstation install-run]$ cp inventory.initial inventory[student@workstation install-run]$ cat inventoryclipboard[student@workstation install-run]$ echo -e "\n[OSEv3:vars]" >> inventory

7.4 配置相关安装版本

 1 [student@workstation install-run]$ vi general_vars.txt 2 #General Cluster Variables 3 openshift_deployment_type=openshift-enterprise			#配置为openshift-enterprise版本 4 openshift_release=v3.9						#配置版本为v3.9 5 openshift_image_tag=v3.9.14 6 openshift_disable_check=disk_availability,docker_storage,memory_availability	#禁用check

7.5 设置htpasswd认证

 1 [student@workstation install-run]$ openssl passwd -apr1 redhat 2 $apr1$/d1L7fdX$duViLRE.JG012VkZDq8bs0 3 [student@workstation install-run]$ openssl passwd -apr1 redhat 4 $apr1$rUMMfQfD$J8CEqQK.YenyNwYwKN1lA1				#创建两个用户密码都为redhat 5 [student@workstation install-run]$ vi authentication_vars.txt 6 #Cluster Authentication Variables 7 openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', 'challenge': 'true', 'kind': 'HTPasswdPasswordIdentityProvider', 'filename': '/etc/origin/master/htpasswd'}] 8 openshift_master_htpasswd_users={'admin':'$apr1$/d1L7fdX$duViLRE.JG012VkZDq8bs0', 'developer':'$apr1$rUMMfQfD$J8CEqQK.YenyNwYwKN1lA1'}

7.6 配置集群网络

 1 [student@workstation install-run]$ vi networking_vars.txt 2 #OpenShift Networking Variables 3 os_firewall_use_firewalld=true					#开启firewall防火墙 4 openshift_master_api_port=443					#启用端口 5 openshift_master_console_port=443				  #启用控制端口 6 openshift_master_default_subdomain=apps.lab.example.com		#指定subdomain

7.7 配置NFS

 1 [student@workstation install-run]$ vi persistence_vars.txt 2 #NFS is an unsupported configuration 3 openshift_enable_unsupported_configurations=true 4  5 #OCR configuration variables 6 openshift_hosted_registry_storage_kind=nfs 7 openshift_hosted_registry_storage_access_modes=['ReadWriteMany'] 8 openshift_hosted_registry_storage_nfs_directory=/exports 9 openshift_hosted_registry_storage_nfs_options='*(rw,root_squash)' 10 openshift_hosted_registry_storage_volume_name=registry 11 openshift_hosted_registry_storage_volume_size=40Gi 12  13 #OAB's etcd configuration variables 14 openshift_hosted_etcd_storage_kind=nfs 15 openshift_hosted_etcd_storage_nfs_options="*(rw,root_squash,sync,no_wdelay)" 16 openshift_hosted_etcd_storage_nfs_directory=/exports 17 openshift_hosted_etcd_storage_volume_name=etcd-vol2 18 openshift_hosted_etcd_storage_access_modes=["ReadWriteOnce"] 19 openshift_hosted_etcd_storage_volume_size=1G 20 openshift_hosted_etcd_storage_labels={'storage': 'etcd'}

7.8 配置离线仓库

 1 #Modifications Needed for a Disconnected Install 2 oreg_url=registry.lab.example.com/openshift3/ose-${component}:${version}	#添加内部仓库 3 openshift_examples_modify_imagestreams=true					#修改IS 4 openshift_docker_additional_registries=registry.lab.example.com		#内部仓库至docker配置 5 openshift_docker_blocked_registries=registry.access.redhat.com,docker.io	#禁止外部官方仓库 6 #Image Prefixes 7 openshift_web_console_prefix=registry.lab.example.com/openshift3/ose- 8 openshift_cockpit_deployer_prefix='registry.lab.example.com/openshift3/' 9 openshift_service_catalog_image_prefix=registry.lab.example.com/openshift3/ose- 10 template_service_broker_prefix=registry.lab.example.com/openshift3/ose- 11 ansible_service_broker_image_prefix=registry.lab.example.com/openshift3/ose- 12 ansible_service_broker_etcd_image_prefix=registry.lab.example.com/rhel7/

7.9 设置label

[student@workstation install-run]$ vi inventory
 1 …… 2 [nodes] 3 master.lab.example.com 4 node1.lab.example.com openshift_node_labels="{'region':'infra', 'node-role.kubernetes.io/compute':'true'}" 5 node2.lab.example.com openshift_node_labels="{'region':'infra', 'node-role.kubernetes.io/compute':'true'}"

7.10 合并并校对Inventory

[student@workstation install-run]$ cat general_vars.txt networking_vars.txt authentication_vars.txt persistence_vars.txt disconnected_vars.txt >> inventory[student@workstation install-run]$ lab install-run grade #本环境提供检查Inventory的脚本[student@workstation install-run]$ cat inventory
 1 [student@workstation install-run]$ cat general_vars.txt networking_vars.txt authentication_vars.txt persistence_vars.txt disconnected_vars.txt >> inventory 2 [student@workstation install-run]$ lab install-run grade		#本环境提供检查Inventory的脚本 3 [student@workstation install-run]$ cat inventory 4 [workstations] 5 workstation.lab.example.com 6  7 [nfs] 8 services.lab.example.com 9  10 [masters] 11 master.lab.example.com 12  13 [etcd] 14 master.lab.example.com 15  16 [nodes] 17 master.lab.example.com 18 node1.lab.example.com openshift_node_labels="{'region':'infra', 'node-role.kubernetes.io/compute':'true'}" 19 node2.lab.example.com openshift_node_labels="{'region':'infra', 'node-role.kubernetes.io/compute':'true'}" 20  21 [OSEv3:children] 22 masters 23 etcd 24 nodes 25 nfs 26  27 #Variables needed by classroom host preparation playbooks. 28 [nodes:vars] 29 registry_local=registry.lab.example.com 30 use_overlay2_driver=true 31 insecure_registry=false 32 run_docker_offline=true 33 docker_storage_device=/dev/vdb 34  35  36 [OSEv3:vars] 37 #General Cluster Variables 38 openshift_deployment_type=openshift-enterprise 39 openshift_release=v3.9 40 openshift_image_tag=v3.9.14 41 openshift_disable_check=disk_availability,docker_storage,memory_availability 42 #OpenShift Networking Variables 43 os_firewall_use_firewalld=true 44 openshift_master_api_port=443 45 openshift_master_console_port=443 46 openshift_master_default_subdomain=apps.lab.example.com 47 #Cluster Authentication Variables 48 openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', 'challenge': 'true', 'kind': 'HTPasswdPasswordIdentityProvider', 'filename': '/etc/origin/master/htpasswd'}] 49 openshift_master_htpasswd_users={'admin':'$apr1$/d1L7fdX$duViLRE.JG012VkZDq8bs0', 'developer':'$apr1$rUMMfQfD$J8CEqQK.YenyNwYwKN1lA1'} 50  51 #NFS is an unsupported configuration 52 openshift_enable_unsupported_configurations=true 53  54 #OCR configuration variables 55 openshift_hosted_registry_storage_kind=nfs 56 openshift_hosted_registry_storage_access_modes=['ReadWriteMany'] 57 openshift_hosted_registry_storage_nfs_directory=/exports 58 openshift_hosted_registry_storage_nfs_options='*(rw,root_squash)' 59 openshift_hosted_registry_storage_volume_name=registry 60 openshift_hosted_registry_storage_volume_size=40Gi 61  62 #OAB's etcd configuration variables 63 openshift_hosted_etcd_storage_kind=nfs 64 openshift_hosted_etcd_storage_nfs_options="*(rw,root_squash,sync,no_wdelay)" 65 openshift_hosted_etcd_storage_nfs_directory=/exports 66 openshift_hosted_etcd_storage_volume_name=etcd-vol2 67 openshift_hosted_etcd_storage_access_modes=["ReadWriteOnce"] 68 openshift_hosted_etcd_storage_volume_size=1G 69 openshift_hosted_etcd_storage_labels={'storage': 'etcd'} 70  71 #Modifications Needed for a Disconnected Install 72 oreg_url=registry.lab.example.com/openshift3/ose-${component}:${version} 73 openshift_examples_modify_imagestreams=true 74 openshift_docker_additional_registries=registry.lab.example.com 75 openshift_docker_blocked_registries=registry.access.redhat.com,docker.io 76  77 #Image Prefixes 78 openshift_web_console_prefix=registry.lab.example.com/openshift3/ose- 79 openshift_cockpit_deployer_prefix='registry.lab.example.com/openshift3/' 80 openshift_service_catalog_image_prefix=registry.lab.example.com/openshift3/ose- 81 template_service_broker_prefix=registry.lab.example.com/openshift3/ose- 82 ansible_service_broker_image_prefix=registry.lab.example.com/openshift3/ose- 83 ansible_service_broker_etcd_image_prefix=registry.lab.example.com/rhel7/

7.11 执行安装剧本

[student@workstation install-run]$ ansible-playbook /usr/share/ansible/openshift-ansible/playbooks/prerequisites.yml#执行准备工作playbookclipboard[student@workstation install-run]$ ansible-playbook /usr/share/ansible/openshift-ansible/playbooks/deploy_cluster.ymlclipboard提示:整个部署log保存至本地目录的ansible.log中。

八 验证测试

8.1 确认验证说明

要验证OpenShift安装,必须测试和验证所有OpenShift组件。仅仅从示例容器映像启动pod是不够的,因为这并不使用OpenShift builders、deployer、router或内部registry。
  • 建议通过以下方式完整验证OpenShift:
  • 检查所有OpenShift节点状态;
  • 检查相应的OpenShift registry和router的pod;
  • 使用OpenShift从源代码构建一个应用程序,OpenShift从构建结果生成容器image,并从该映像启动pod;
  • 创建一个service,以便可以从内部容器网络和OpenShift节点访问应用程序;
  • 创建一个route,以便可以从OpenShift集群外部的计算机访问应用程序。
安装完成后,OpenShift客户端可以使用oc,master节点可以使用oadm命令。master节点的root用户将被配置为云管理员的身份运行OpenShift客户机和管理员命令。一些OpenShift内部服务,如内部仓库和router,默认情况下由安装程序配置。运行oc get nodes和oc get pods命令,以验证安装成功。

8.2 登录测试

浏览器访问:https://master.lab.example.comclipboardclipboard

8.3 验证OpenShift功能

[student@workstation ~]$ oc login -uadmin -predhat https://master.lab.example.comclipboard提示:账号权限需要单独授予,安装过程中创建的adminn并没有集群的administration特权。

8.4 授予权限

system:admin是唯一一个拥有集群administration权限的账户。master节点的root用户被都为集群的system:admin用户。[root@master ~]# oc whoamisystem:admin[root@master ~]# oc adm policy add-cluster-role-to-user cluster-admin admin #添加admin为集群管理员提示:cluster-admin角色权限非常高,允许管理用户销毁和修改集群资源,必须谨慎使用。

8.5 查看节点状态

再次使用命令登录。[student@workstation ~]$ oc login -uadmin -predhat https://master.lab.example.comclipboard[student@workstation ~]$ oc get nodesNAME STATUS ROLES AGE VERSIONmaster.lab.example.com Ready master 14h v1.9.1+a0ce1bc657node1.lab.example.com Ready compute 14h v1.9.1+a0ce1bc657node2.lab.example.com Ready compute 14h v1.9.1+a0ce1bc657[student@workstation ~]$ oc get podsNAME READY STATUS RESTARTS AGEdocker-registry-1-4w5tb 1/1 Running 1 14hdocker-registry-1-j7k59 1/1 Running 1 14hregistry-console-1-mtkxc 1/1 Running 1 14hrouter-4-9dfxc 1/1 Running 0 4hrouter-4-kh7th 1/1 Running 0 5h

8.6 创建项目

[student@workstation ~]$ oc new-project smoke-test

8.7 创建应用

[student@workstation ~]$ oc new-app --name=hello -i php:7.0 ~]$ oc get pods -w #监视pod创建

8.8 查看route

[student@workstation ~]$ oc get routesNAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARDhello hello-smoke-test.apps.lab.example.com hello 8080-tcp None

8.9 公开服务

[student@workstation ~]$ oc expose service hello #向外部网络公开服务

8.10 测试服务

[student@workstation ~]$ curl World! php version is 7.0.10[student@workstation ~]$ oc delete project install-post #删除项目

8.11 测试developer

[student@workstation ~]$ oc login -u developer #使用redhat密码登录[student@workstation ~]$ oc new-project smoke-test[student@workstation ~]$ oc new-app php:5.6 --name hello[student@workstation ~]$ oc logs -f bc/hello #监视构建过程提示:输出表明OpenShift能够从仓库clone代码、并且构建image,同时将新image推入内部仓库。[student@workstation ~]$ oc expose svc hello route "hello" exposed[student@workstation ~]$ oc get routesNAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARDhello hello-smoke-test.apps.lab.example.com hello 8080-tcp None[student@workstation ~]$ curl hello-smoke-test.apps.lab.example.comHello, World! php version is 5.6.25
002.OpenShift安装与部署