持续交付+springboot+k8s


容器化部署持续交付

1,课程导学

snapshot 是开发版本
release 是发布版本

devOps(敏捷开发)

2,如何持续集成

计划--->代码--->构建(敏捷开发)--->测试(持续集成)--->发布(持续交付)--->部署(持续部署)--->运维(devOps)

jenkins--->ansible--->Vault--->不同环境

发布
    灰度(蓝绿发布)
        先一小部分用户体验新版本
    金丝雀发布
        部署25%的机器,根据监控数据决策是否进一步部署
    开关功能
        前后端功能没对接功能可用开关控制后先部署

3,需求任务管理

使用Jira创建Sprint,用户故事和任务
    敏捷项目管理和Jira
        release(月)
            sprint(周)
                issue(问题)
                    epic(史诗)
                    story(用户故事)
                    task(任务)
                    bug(故障)
    创建Sprint(冲刺)
        sprint需要关联带开发的任务
        sprint需要被关联到某一个release
    创建用户故事
        定义用户故事的类型
        定义用户故事的内容描述
        分配给某个开发者
    创建任务,并分配给工程师
        将任务与用户故事关联
        将任务放入sprint中

任务的排期和追踪
    查看release版本信息
        查看release任务
            为任务预估story point
            工作量
            复杂度
            风险和不确定性
    查看sprint
    查看sprint各个任务的进度
        创建任务燃尽图
    每日站会如何开
        昨天做了什么,今天要做什么,有什么阻塞问题,需要什么帮助

docker 安装jira

#!/bin/bash

docker build -t mysql .
# docker run --name mysql8.0 --privileged=true -v /home/project/mysql/conf:/etc/mysql -v /home/project/mysql/logs:/logs -v /home/project/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=swj5201314 -p 3306:3306 -d mysql:8.0
docker run -p 3306:3306 --name mysql -v /home/project/mysql/conf:/etc/mysql -v /home/project/mysql/logs:/var/log/mysql -v /home/project/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=swj5201314 -d mysql:5.7 --default-storage-engine=INNODB --character_set_server=utf8mb4 --innodb_default_row_format=DYNAMIC --innodb_large_prefix=ON --innodb_file_format=Barracuda --innodb_log_file_size=2G

# mysql8.0
# mysql -u root -p #登录
# use mysql; #选择数据库
# 远程连接请将'localhost'换成'%'
# ALTER USER 'root'@'%' IDENTIFIED BY 'Swj5201314' PASSWORD EXPIRE NEVER; #更改加密方式
# ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'Swj5201314'; #更新用户密码
# FLUSH PRIVILEGES; #刷新权限

# my.cnf

# [mysqld]
# pid-file        = /var/run/mysqld/mysqld.pid
# socket          = /var/run/mysqld/mysqld.sock
# datadir         = /var/lib/mysql
# secure-file-priv= NULL

## Custom config should go here
# secure_file_priv=/var/lib/mysql

# default-storage-engine=INNODB
# character_set_server=utf8mb4
# innodb_default_row_format=DYNAMIC
# innodb_log_file_size=2G
## remove this if it exists
## sql_mode = NO_AUTO_VALUE_ON_ZERO

# mysql5.7
# CREATE DATABASE jiradb CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
# GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,ALTER,INDEX on jiradb.* TO 'root'@'%' IDENTIFIED BY 'swj5201314';
# flush privileges;


#!/bin/bash
docker build -t jira .
docker run -v /home/project/jira/jiraData:/var/atlassian/application-data/jira --name=jira -d --restart always -p 8080:8080 atlassian/jira-software
docker exec --user root jira mv /opt/atlassian/jira/atlassian-jira/WEB-INF/lib/atlassian-extras-3.4.6.jar /opt/atlassian/jira/atlassian-jira/WEB-INF/lib/atlassian-extras-3.4.6.jar_bak
# docker cp atlassian-extras-3.2.jar jira:/opt/atlassian/jira/atlassian-jira/WEB-INF/lib/
docker cp atlassian-agent.jar jira:/opt/atlassian/jira/
docker cp mysql-connector-java-8.0.27.jar jira:/opt/atlassian/jira/atlassian-jira/WEB-INF/lib/
docker restart jira

# jdbc:mysql://120.78.81.53:3306/jiradb?autoReconnect=true&useUnicode=true&characterEncoding=UTF8
# com.mysql.jdbc.Driver

# 破解
# java -jar atlassian-agent.jar -d -m [email protected] -n XINGYUE -p jira -o http://120.78.81.53 -s BQ3E-7TIT-ZETL-TCKE

# AAAB4g0ODAoPeNp9kl9zmkAUxd/5FMz0pZ0OBIiicYaZJrhWWkALWuKMLytedRNZyC6o5NOXfxmtGh8X7j33d8+5XwJYim68E7WWqCi9druntkTTn4iaoqnCK+R/gXESU0PVFaWjdO/vVWHNAOgmThJgsk1CoBzQkqRlFXInyBt7lo8EN4sWwEarKS8UDEkVzJimOExdHIGR7xeqInd/vL3JYRwJL4Rh+aJhnLFwgzn0cQpGySOpqqS1hGbmJE+gEjNHjoM803q0P36hQ0JYftKnlX0NAHIw2Z4T+MB2wKy+8eTpHUmfBbYUDNpTadRFQY2XsHiZhalcPiQer9I9ZiAXemQHRsoyuFVWoGATaAqsLt3WnEPMN4Zj7s3B0J1G6Pf7bPB6uLMdZ/hzrAeHRRTRFn/ceG3Tj/Ds6XvwjPJnmpprxXvZWlaqt/7Mjbkh+NmCh4wkVQZHls/DuRLhNTsLpwpmimn4iaU3Vr6Is5lTeGxbfR+5kq12Og+a3lZrmXOPihLjStn1aX6KWdm5wlsOwoitMSUcV2sfCF3nGbxvSJ5RwWRQfT4/qiaRj3PX/rOookoY4U3SfTja/avgEP2GQ/xabiHWa3yb90S0w9usGljTX9zLDfdPCU77jpr1+x8vdEosMCwCFBqrnaeoM9DYMePkober+TAWltNuAhQ6GqlBXAvFdth4kUKnjz7vsWuZqg==X02mu

# xingyue
# xingyue@5201314


在开发工具里集成jira插件
    在idea里集成jira插件
        jira integration
            Tasks
                Servers
    在idea里快速获取自己的开发任务
    通过插件创建分支,开发代码
    提交代码并更改jira任务状态

gitflow vs Trunk base 分支模型哪个更适合团队
    gitflow 是一种分支开发模型
        master 线上分支
        develop 开发主分支
            所有分支最后都需要合并到develop分支
        feature 功能分支
            分支名称 feature-*
        release 发布分支
            分支名称 release-*
        hotfix 功能修复分支
            分支名称 hotfix-*
        适用场景
            软件本身对稳定性要求高
            团队少量资深研发,多数初,中级研发
            开源项目
        功能开关
    主干开发分支模型
        适用场景
            软件本身迭代较快
            团队中级,资深研发较多,初级研发较少
            互联网产品

开发一个springboot 项目
    
创建springcloud服务注册中心
    依赖/注解/配置

在服务应用前端加上网关
    springcloud zuul 网关用法
        zuul:
            routes:
                guestbook:
                    path: /**
                    serviceId: guestbook-service

        zuul:
            routes:
                guestbook:
                    path: /**
                    uri: http://service:8080/guestbook/

服务链路追踪zipkin

docker run --name zipkin -d -p 9411:9411 openzipkin/zipkin

应用添加配置
spring:
  zipkin:
    base-url: http://localhost:9411

搭建maven私服
搭建JFrog Artifactory OSS 开源
创建Maven仓库
配置Maven连接到Arifactory

搭建JFrog Artifactory OSS 开源版
使用docker
export JFROG_HOME=/Users/xingyue/.jfrog/JFROG_HOME
# export JFROG_HOME=/home/docker-jfrog/.jfrog/JFROG_HOME
docker run -d --name artifactory-oss-6.18.1 -v /Users/xingyue/Home/xingyue/学习/工程化/artifactory:/var/opt/jfrog/artifactory -p 8081:8081 docker.bintray.io/jfrog/artifactory-oss:6.18.1

注意使用ip访问
默认用户名/密码 admin/password

maven仓库结构
开发者 ---> git ---> jenkins(service) ---> artifactory(local/remote(下载到jenkins) ---> JCenter)

进入界面Artifact Repository Browser
1,使用虚拟仓库libs-release
    新建远程仓库,新建本地仓库,新建虚拟仓库(将本地和远程一起添加)
2,生成settings.xml文件,替换到maven的settings.xml文件

发布应用到maven私服
artifact repsitory browser ---> libs-release ---> set me up

   
        central
        releases
        http://localhost:8083/artifactory/libs-release
   

mvn package
mvn deploy

根据version自动区分打到那个仓库

元数据打标签 properties

命名规范
面板 admin ---> layouts ---> maven-2-default
[orgPath]/[module]/[baseRev](-[folderItegRev])/[module]-[baseRev](-[fileItegRev])(-[classifier]).[ext]

使用curl下载制品包 右上角用户信息 ---> edit profile --->apikey
输入账号密码

AKCp8k8srBKRuXbGYJXMrQbH4i5Gz8rVhn869DmSH21Un4nhPqzJD5rq3j5PnswGe9a4UPVMJ

curl -u admin:AKCp8k8srBKRuXbGYJXMrQbH4i5Gz8rVhn869DmSH21Un4nhPqzJD5rq3j5PnswGe9a4UPVMJ http://120.78.81.53:8081/articactory/libs-release-local/com/xingyuezhiyun/gateway-service/1.3/gateway-service-1.3.jar --output gateway-service-1.3.jar


----------自动化测试----------

#!/bin/bash
mkdir jenkins_home
chmod -R 777 `pwd`/jenkins_home
docker run -d -v `pwd`/jenkins_home:/var/jenkins_home -p 8082:8080 -p 50000:50000 jenkins/jenkins:lts-jdk11

查看容器日志获取密码
ff7a5ab958744ad98535516c2f16b961

jenkins 核心
2.0 可以使用pipeline 流水线

jenkins
    project项目
    build构建
    workspace工作空间
    credentials凭据

jenkins 持续集成流水线
    集群执行

    两种语法
        scripted groovy
            脚本式流水线
        declerative 预制的标签进行结构化的编写,功能受限但更加标准化
            声明式流水线严格规范

jenkins 集成Artifactory
    安装jenkins Artifactory 插件
    配置Artifactory插件 http://ip:port/artifactory
    Connect to localhost:8083 [localhost/127.0.0.1] failed: Connection refused (Connection refused)
    配置Artifactory credentials
    在流水线中使用Artifactory进行依赖下载,制品上传

jenkins流水线集成jira
    安装jenkins jira插件 jira plugin
    配置jira credentials
    配置jira插件
    提交代码时,管理jira任务id git commit -m "taskId xxx"
    在构建结果中查看任务id

jenkins 集成sonarqube
    docker pull library/sonarqube:lts
    docker run -d -p 9000:9000 sonarqube
    访问http://localhost:9000
    账号密码 admin/admin
    创建项目,生成token
    携带登录的token

    idea安装sonarqube插件

    jenkins调用sonarqube 接口,获取状态,如果质量太低就构建失败

jenkins 集成接口测试工具YAPI(去哪儿)
    http://github.com/YMFE/yapi

ui自动化测试工具selenium
    https://www.selenuim.dev
    下载 Chrome webDriver
    mac/linux: 将文件放入/usr/local/bin
    在项目中引入依赖
    
        org.seleniumhq.selenium
        selenium-java
        3.141.59
    

    在JUnit中调用ChromeDriver
    在测试用例中寻找按钮并执行点击操作,判断结果是否符合预期

编写单元测试springboot test

idea 安装sonarlint 插件

yapi对接口进行测试
参考官网:https://hellosean1025.github.io/yapi/devops/index.html


----------自动化运维----------

Ansible 配置管理和应用部署的工具
Control node 控制节点
Managed nodes 受管控节点
Inventory 库存表
Modules 模块
Tasks 任务
Playbooks 剧本

Ansible 安装和配置
安装python
yum install ansible -y

创建软连接
mac
sudo ln -s /Users/xingyue/Library/Python/3.9/bin/ansible /usr/bin/ansible

创建基础的库存表
vi /etc/ansible/hosts
all: 
    hosts:
        maol.example.com
    children: 
        webservers:
            hosts:
                foo.example.com
                bar.example.com
aaa.com
默认在[all]组下

[webservers] 组
xxx.com
yyy.com

设置变量给playbook使用

Ansible的配置

远程主机免密登录
配置ssh生产ssh-key
1,管理节点生产ssh-key
ssh-keygen
2,拷贝当前主机的ssh key到远程主机,ip地址替换为远程地址
ssh-copy-id [email protected]
3,保存远程主机ip,保存到当前主机的known_host
ssh-keyscan prod.server >> ~/.ssh/konwn_hosts
ssh [email protected]

cat /etc/ansible/hosts
[prod] #定义生产组
prod.server # 远程服务地址
ansible all -m ping -u root
ansible prod -m copy -a "src=note-book-1.0.jar dest=/tmp" -u root

Ad-hoc 命令
用来重启机器,拷贝文件,管理包和用户
管理用户和组
ansible all -m user -a "name=foo state=absent"
管理服务
ansible webservers -m service -a "name=httpd" state=started
获取系统变量
ansible all -m setup -u root

重启服务器
ansible beijing -a "/sbin/reboot"
管理文件
ansible beijing -m copy -a "src=/etc/hosts dest=/tmp/hosts"
管理包
ansible beijing -m yum -a "name=acme state=latest"

Ansible playbook 介绍
复杂的部署编排场景,同步或者异步的发起任务
一组机器被映射为定义好的角色,playbook的内容被称为tasks,一个任务是一个对ansible模块的调用
语言介绍
基础
执行一个playbook
- hosts: prod # [webservers]
  vars:
    http_port: 80
    max_clients: 200
  remote_user: root
  tasks:
    - name: ping
      ping:
       remote_user:xxx # 用户控制
     - name:ensure apache is at the latest version
       yum: pkg=httpd state=latest
     - name:write the apache config file
       template:src=/srv/httpd.j2 dest=/etc/httpd.conf
       notify:
       - restart apache
     - name ensure apache is running
       service:name=httpd state=started
     handlers:
      - name:restart apache
        service:name=httpd state=restarted

执行
ansible-playbook xxx.yml

可复用的playbook
import xxx.yml
动态vs静态引用
如何使用变量
引用变量{{}}
系统变量
- debug: var=ansible_facts
{{ ansible_facts['devices']['xvda']['model']}}
循环
loop: "{{ groups['all'] }}"
条件 condition
when: 
Roles
用于自动化加载一些默认的变量,任务等
    任务
    handler
    defaults
    vars
    files
    templates
    meta

如果roles/x/tasks/main.yml存在,则里面的任务会被加载到当前的play
---
- hosts: webservers
  roles:
   - common
   - webservers

编写notebook的playbook
-hosts: prod
 remote_user: root
 tasks:
  -name: Copy jar files to prod
   copy: src=notebook-service-1.0.jar dest=/tmp
       owner=root group=root mode=0644
  -name: start jar
   shell: nohup java -jar /tmp/notebook-service-1.0.jar &
  -name: sleep 20 s
   shell: sleep 20
  -name: shut down
   shell: kill-9 $(lsof -t -i:1111)

流水线集成ansible
新增pipe line
node {

    stage('Pull source code') {
       git 'https://git.imooc.com/coding-439/Notebook-k8s.git'

    }
    dir('Final/notebook-service') {
        //构建 Maven
        stage('Build and UI test'){
            sh ' mvn package -Dmaven.test.skip=true'
        }

    }
    dir('Chapter-8') {
        //部署 notebook.jar to remote server

        stage('Ansible Deploy to remote server'){
            sh 'cp ../Final/notebook-service/target/notebook-service-1.0.jar ./'
            sh 'ansible-playbook notebook-playbook.yml'
        }
    }
 }

git clone --depth=1

最佳实践
目录结构
production #生产环境的资源目录
staging #准生产环境的资源目录
group_vars/ 
    group1.yml #某个组的环境变量
host_vars/
    hostname_1.yml #针对某种系统的变量
library/
filter_plugins
site.yml #主要的playbook入口
webservers.yml
dbservers.yml
roles/

区分生产和准生产环境配置
使用不用的文件分别存储不同环境的域名信息
#file: production
[bj_webservers]
www-bj-1.example.com

[sh_webservers]
www-sh-1.example.com

合理利用组
只配置webserver
ansible-playbook -i production webservers.yml

只配置北京的webserver
ansible-playbook -i production webserevers.yml --limit beijing

滚动执行配置北京的webserver
ansible-playbook -i production webservers.yml --limit beijing[0:9]

用roles进行复用

使用roles进行隔离
- import_playbook: webservers.yml
在webservers组中加载默认的role

定义roles的变量(明文)
变量抽取到#file group_vars/dbservers

ansible vault(加密)

实现滚动升级(先升级一个,成功了再升级其他)
升级前
升级后

docker

使用CGroup进行CPU,内存隔离
sys/fs/cgroup/cpu
创建文件夹 设置 cpu.cfs_quota_us进行限流
echo 20000 > /sys/fs/cgroup/cpu/cgroups_test/cpu.cfs_quota_us
将任务进程绑定到当前文件夹的tasks中
echo xxxxx > /sys/fs/cgroup/cpu/cgroups_test/tasks

docker run -it --cpus=.5 xxx /bin/bash

namespace 资源隔离

文件系统隔离
aufs联合挂载
/var/lib/docker/aufs
/diff 管理docker镜像每一层的内容
/layer 管理docker镜像的元数据,层级关系
/mnt 管理挂载点,通常对应一个镜像,或者layer,用于描述一个容器镜像的所有层级内容

docker常用命令

搭建docker镜像仓库
hub.docker.com 镜像中心
JCR
docker run -d --name artifactory-jcr -v /Users/xingyue/Home/xingyue/学习/工程化/jcr/var:/var/opt/jfrog/artifactory -p 8083:8081 -p 8084:8082 docker.bintray.io/jfrog/artifactory-jcr:latest
admin/password
1,为docker客户端增加JCR本地非安全注册中心

远程docker操作(120.78.81.53)
export DOCKER_OPTS+=" --insecure-registry 120.78.81.53:8084"
{
    "insecure-registries": ["120.78.81.53:8084"]
}

尝试本地docker添加"insecure-registries": ["120.78.81.53:8084"]
docker login 120.78.81.53:8084 -uadmin -ppassword
重启后登陆成功

本地docker操作(本机)
Insecure Registry: art.local:8083
2,配置本地域名解析
127.0.0.1 art.local
3,本地docker客户端登录docker镜像中心
docker login art.local:8081 -uadmin -ppassword

上传下载镜像
docker build -t art.local:8081/docker-local/notebook-k8s/notebook-service:latest .
docker push art.local:8081/docker-local/notebook-k8s/notebook-service:latest
docker pull art.local:8081/docker-local/notebook-k8s/notebook-service:latest

docker build -t docker-jcr/notebook-service:latest .
docker push docker-jcr/notebook-service:latest
docker pull docker-jcr/notebook-service:latest

编写notebook的dockerfile
RUN
CMD
ADD
ENTRYPOINT

docker镜像中心
虚拟仓库

dockerfile 最佳实践

避免安装不必要的包
每个容器只关心一个问题
最小化层数
依赖库从制品库中获取,避免在容器中构建,提升镜像构建速度
尽可能使用官方镜像,推荐Debian镜像作为基础镜像,它被严格控制并且保持最小,同时是一个完整的发行版
避免ADD一个远程文件,而应该使用curl或者wget获取远程文件,减少镜像层数
&& curl -SL http://xxx.com/big.tar.xz \ |tar -xJC / usr/src/things

ADD

ENV

在容器中切换目录时使用WORKDIR,避免一下写法
RUN cd ... && dosomething

应该使用WORKDIR命令切换工作目录
WORKDIR
ENV foo/bar
WORKDIR ${foo}

构建微服务的docker镜像,先推送到local仓库
docker login art.local:8081 admin/passw0rd
docker build -t art.local:8081/docker-dev-local/notebook-k8s/notebook-service:latest
docker push att.lcoal:8081/docker-dev-local/notebook-k8s/notebook-service:latest

使用docker运行多个微服务(生成环境不用,使用chart)
docker run --name notebook-service -d -p 1111:1111
--link discovery-service:eureka-server
--link zipkin-service:zipkin-server
art.local:8081/docker/notebook-k8s/notebook-service:latest

jcr仓库制品晋级
在流水线中使用curl脚本晋级docker镜像
HTTP POST : http://localhost:8082/ui/api/v1/ui/artifactactions/copy
{
    "repoKey": "docker-dev-local",
    "path": "notebook-k8s/notebook-service/latest",
    "targetRepoKey": "docker-release-local",
    "targetPath": "notebook-k8s/notebook-service/latest"
}


搭建minikube

linux

minikube 不能以root方式启动,我们先创建个账号并且切过去

sudo useradd xingyue -g docker
passwd xingyue

1.切换到超级用户:$ su
2.打开/etc/sudoers文件:$vim /etc/sudoers
3.修改文件内容:
找到“root    ALL=(ALL)       ALL”一行,在下面插入新的一行,内容是“hadoop   ALL=(ALL)       ALL”,然后在vim键入命令“:wq!”保存并退出。

sudo groupadd docker
sudo usermod -aG docker ${USER}
sudo su - docker

yum update & yum clean all & yum list

curl -Lo kubectl http://kubernetes.oss-cn-hangzhou.aliyuncs.com/kubernetes-release/release/v1.20.0/bin/linux/amd64/kubectl && chmod +x ./kubectl && mv ./kubectl /usr/local/bin/kubectl;
curl -Lo minikube http://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/releases/v1.20.0/minikube-linux-amd64 && chmod +x ./minikube && mv ./minikube /usr/local/bin/minikube;

mac
curl -Lo kubectl http://kubernetes.oss-cn-hangzhou.aliyuncs.com/kubernetes-release/release/v1.20.0/bin/darwin/amd64/kubectl && chmod +x ./kubectl && mv ./kubectl /usr/local/bin/kubectl
curl -Lo minikube http://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/releases/v1.20.0/minikube-darwin-amd64 && chmod +x ./minikube && mv ./minikube /usr/local/bin/minikube

版本 v1.16.0

yum install -y conntrack

启动 2核8G(需要比分配给docker的内存小)

root用户启动,可能有问题
# minikube start --driver=none

其他用户(xingyue)启动
minikube start --driver=docker

# minikube start --cpus 2 --memory=8192mb;

# ! To use kubectl or minikube commands as your own user, you may need to relocate them. For example, to overwrite your own settings, run:
# * 
#   - sudo mv /root/.kube /root/.minikube $HOME
#   - sudo chown -R $USER $HOME/.kube $HOME/.minikube
# * 
# * This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true

minikube status

启动docker镜像中心jcr
配置In-secure私有镜像中心
将本地docker镜像中心添加到Minikube中docker引擎的非安全白名单
/Users/xingyue/.minikube/machines/minikube/config.json

"120.78.81.53:8084"

docker login 120.78.81.53:8084 -uadmin -pXingyue5201314

添加minikube里jcr的域名解析

minikube ssh

su

sudo echo "172.19.200.145 art.local" >> /etc/hosts

kubectl create deployment nginx --image=nginx

minikube dashboard

端口在下面开启,同时在阿里云打开
用kubectl做个代理,代理到外网ip上

xingyue用户设置ip代理,记得要开启阿里云安全组,这样就能在外部访问了
nohup kubectl proxy --port=35960 --address='172.18.186.11' --accept-hosts='^.*' &
这行命令表示 该命令后台常驻运行。
并且暴漏外面端口 33721,代理地址到172.18.186.11 允许所有人访问。
然后我阿里云内网ip 192.168.0.191 自动转发到我阿里云外网ip,我就可以通过外网打开 dashboard了

利用命名空间为不同团队创建kubernates环境
多团队需要不同的kubernetes环境进行测试,生产部署
根据用户进行资源配额

default 默认命名空间
kube-system 环境使用的空间
kube-public 自动创建, 对所有用户可见,全局共享的资源使用

kubectl create namespace dev
kubectl delete namespace sit
kubectl run nginx --image=nginx -n dev

在dev namespace中创建pod
kubectl create -f k8s-deploy/discovery.yaml -n prod
kubectl get po -n dev

在kubernetes中创建pod
核心概念
cluster
    namespace
    nodes
    persistent volumes
    roles
    storage classes
workloads
    cron jobs
    daemon sets
    deployments
    jobs
    pods
    replica sets
    replication controllers
    stateful sets
discovery and load balancing
    ingress
    services
config and storage
    config maps
    persistent volume claims
    secrets

pod生命周期
pending 某一个容器没有被成功创建
running pod被分配到某个node正常运行
succeeded 正确终止
fail 至少有一个容器没有被正确终止
unkonw 失去通信

创建一个pod
kubectl run --image=nginx nginx-app --port=80
deployment.apps/nginx-app created
kubectl get pods
kubectl describe pods

一个pod一个容器(应用广泛), 共享资源
一个pod多个容器(共享资源,不好控制)

3种控制器
Deployment 维护pod在集群内部的部署和扩容
StatefulSet 维护有状态的pod在集群内部的部署和扩容(有编号)
DaemonSet 保证在集群的各个node上pod的副本在运行

创建notebook应用的service

用来描述pod
定义一个service
apiVersion: v1
kind: Service
metedata:
    name: my-service
spec:
    selector:
        app: Myapp
    ports:
       -protpcol: TCP
         port: 80
         targetPort: 9376

service 对外暴露服务的方法
ClusterIP
NodePort
LoadBalancer(生产推荐)
External Name 外部域名

集群内部如何发现需要的Service
Environment variavles(系统环境变量)
当pod运行在node上,kubelet会为容器增加当前活动的service作为环境变量进行域名解析
{SVCNAME_SERVICE_HOST} {SVCNAME}_SERVICE_PORT (service名字会被转化成大写)

进入容器
kubelet exec -it xxx /bin/sh
printenv

DNS
cluster-aware DNS server -CoreDNS
kubectl get po
kubectl exec -it xxx /bin/sh
printenv

service 和 pod之间的调度 kube-proxy

随机

iptables

ipvs proxy mode (生产推荐) 可配置以什么为最优
IPVS规则和kubernetes
service定期同步
直接重定向最优服务器
性能优于Iptalbes Proxy

kubectl delete -f xxx.yaml
nodeport 指定端口

持久化存储
volumes 类型
emptydir 生命周期和pod相同 检查点,临时存放文件
local 必须配置nodeAffinity
nfs 共享存储
persistentVolumeClaim 持久化存储
cephfs 
glusterfs 分布式多写

access mode
ReadWriteOnce 卷可以被单个node挂载为可读写卷
ReadOnlyMany 卷可以被多个node挂载为只读卷
ReadWriteMany 卷可以被多个node挂载为可读写卷

在Deployment中声明卷的挂载
在Deployment中声明PVC进行PV的匹配
storageClassName匹配
selector匹配存储的逻辑分类
这样即使重启,也不会丢失数据

声明pv
kind: PersistentVolume
apiVersion:v1
metadata:
    name: task-pv-volume
    labels:
        type: local
spec:
    storageClassName: manual
    capacity:
        storage: 3Gi
    accessModes: 
      - ReadWriteOnce
    hostPath:
        path: "/data/jenkins-home"

使用pv
spec: 
    containers:
      - name: jenkins
        image: jenkins/jenkins:lts
        ports:
          - containerPort: 8080
        volumeMounts: 
          - name: task-pv-storage
            mountPath: "/var/jenkins_home"
    volumes: 
      - name: task-pv-storage
          persistentVolumeClaim: 
              claimName: task-pv-claim

为notebook创建deployment
提供pod和ReplicaSets的更新管理
Workloads
    Pods
    Controllers
        ReplicaSet
        ReplicationController
        Deployments
        StatefulSets
        DaemonSet
        Garbage Collection
        TTL Controller for Finished Resources
        Jobs - Run to Completion
        CronJob

kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata: 
    name: nginx-deployment
    labels:
        app: nginx
spec:
    replicas: 3
    selector:
        matchLabels:
            app: nginx
    template:
        metadata:
            labels:
                app: nginx
        spec:
            containers:
                -name: nginx
                image: nginx:1.14.2
                ports:
                    - containerPort: 80

kubectl get deployments

更新deployment(版本升级)
kubectl --record deployment.apps/nginx-deployment set image deployment.v1.apps/nginx-deployment nginx=nginx:1.16.1

deployment.apps/nginx-deployment image updated
其中--record用于记录每次Deployment的差异

kubectl get rs

kubectl get pods

deployment 会保持副本数

deployment部署失败可能的原因
配额不够
Readiness探针检测失败
image拉取失败
权限访问不到
超出了资源限制范围
应用运行时配置错误

为 pod 创建探针
livenessProbe 表示容器是否运行
readinessProbe 表示容器内的应用是否可以开始提供服务
startupProbe 表示容器内部的应用已经启动,如果设置了该探针,在它成功之前,其他类型的探针不会生效

execAtion探针 在容器内部执行特定命令
apiVersion: v1
kind: Pod
metadata:
    labels:
        test:liveness
    name: liveness-exec
spec:
    containers:
      - name: liveness
        image: k8s.gcr.io/busybox
        args: 
          - /bin/sh
          - -c
          - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
          livenessprobe:
              exec:
                  command:
                    - cat
                    - /tmp/healthy
              initialDelaySeconds: 5
              periodSeconds: 5
TCPSocketAction 调用TCP请求确认容器是否正常服务
HTTPGetAction探针 发起一个http get 请求访问应用的某个端口和路径
livenessprobe:
      httpGet:
          path: /
          port: 8761
      initialDelaySeconds: 15
      periodSeconds: 15

kubectl describe pod notebook-service-xx-xx 可以查看探针的状态

为应用添加configmap
apiVersion: v1
kind: ConfigMap
metadata:
    name: game-demo
data:
    play_inital_lives: 3
    ui_properties_file_name: "user-interface.properties"
    game.properties: /
        enemy.types=aliens,monsters
        player.maximum-lives=5
    user-interface.properties: /
        color.good=purple
        color.gad=yellow
        allow.textmode=true

存在etcd
明文
4种方式引用configmap
1,通过命令行参数的方式注入到容器的entrypoint
2,容器的环境变量
3,在卷中增加一个只读文件,供所有应该读取
4,在应用代码中调用kbs的api,读取configmap的信息
创建configmap
kubectl create configmap special-config --form-literal=special.how=very
创建configmapTest.yaml
kubectl create -f configmapTest.yaml
command:["/bin/sh", "-c", "env"]

apiVersion: v1
kind: Pod
metadata:
    name: dapi-test-pod
spec:
    containers:
      - name: test-container
          image: k8s.gcr.io/busybox
          command: ["/bin/sh", "-c", "env"]
          env:
            - name: SPECIAL_LEVEL_KEY
                valueFrom:
                    configMapKeyRef:
                        name: special-config
                        key: special.how
    restartPolicy: Never

kubectl logs xxx-xx-xxx

部署notebook微服务到k8s
常用命令
create kubectl create -f filename 创建一个或多个资源
apply kubectl apply -f filename 对某个资源进行变更
exec kubectl exec POD command 在pod中执行命令
get kubectl get type 列出一个或多个资源
logs kubectl 打印pod中容器的日志
top kubectl top 列出集群中的资源消耗情况
describe kubectl describe type 列出资源信息
delete kubectl delete -f pod.yaml 删除某些k8s对象

-o

--sort by (过滤)

-n (限定命名空间)

kubelet get svc

minikube ip

kubectl logs pod-name -f
sidecar
fluentD agent

pod 添加密钥
k8s的secret
作为文件挂载到一个或多个容器
作为容器的环境变量使用
在容器启动时,从kubelet从镜像中心拉取镜像

1,创建一个本地文件
echo -n 'admin' > ./username.txt
echo -n '1f2d1e2e67df' > ./password.txt

2,创建secret对象
kubectl create secret generic db-user-pass --form-file=./username.txt --from-file=./password.txt
kubectl get secrets
kubectl delete secrets xxx-xxx-xxx

3,创建一个docker镜像的secret
kubectl create secret docker-registry regcred-local --docker-server=art.local:8081 --docker-username=admin --docker-password=passw0rd [email protected] -n dev

4,查看日志
secret "db-user-pass" created

秘钥管理的最佳实践
1,管理员应该启用etcd文件目录的加密
2,管理员应该限制etcd的访问权限
3,管理员要定期删除etcd的文件和磁盘,如果不再使用的话
4,如果在集群里运行etcd,管理员应该启用SSL/TSL的通信

使用RBAC基于角色的权限控制管理密钥
service count
秘钥的watch和list的请求权限应该被保留在有限的系统管理员
为应用提供一个有限的秘钥访问白名单


helm入门
管理复杂的多容器部署
tar -zxvf helm-v3.0.0-linux-amd64.tar.gz
mv linux-amd64/helm /usr/local/bin/helm

在JCR中创建Helm远程仓库
远程仓库可以指向国内源:http://mirror.azure.cn/kubernetes/charts/

在本地配置远程仓库
helm repo add stable http://120.78.81.53:8081/artifactory/helm

setme up
helm repo add helm-virtual http://120.78.81.53:8084/artifactory/api/helm/helm-virtual --username admin --password Xingyue@5201314
helm repo update

helm install stable/mysql --generate-name
helm ls

创建第一个Helm Chart
helm create foo
部署一个helm chart到kubernetes
helm install --set name=prod myredis ./redis
覆盖
helm install -f myvalues.yaml -f override.yaml myredis ./redis

从helm仓库安装
helm install mymaria example/mariadb

安装一个helm chart包
helm install mynginx ./nginx-1.2.3.tgz

从Chart目录安装
helm install mynginx ./nginx

从Chart绝对路径安装
heml install mynginx https://example.com/chart/nginx-1.2.3.tgz

指定仓库路径安装
helm install --repo https://example.com/charts/mynginx nginx

更新,一键升级
helm upgrade -f myvalues.yaml -f override.yaml redis ./redis

charts 目录存放依赖的chart
Chart.yaml 包含Chart的基本信息,包括chart版本,名称等
templates 目录下存放应用一系列 k8s 资源的 yaml 模板
    _helpers.tpl 此文件中定义一些可重用的模板片断,此文件中的定义在任何资源定义模板中可用
    NOTES.txt 介绍chart 部署后的帮助信息,如何使用chart等
values.yaml 包含了必要的值定义(默认值), 用于存储 templates 目录中模板文件中用到变量的值

为notebook服务创建helmchart
在jcr镜像仓库中创建helm-local仓库
远程仓库可以指向国内源
http://mirror.azure.cn/kubernetes/charts/
在jcr中创建helm虚拟仓库
虚拟仓库聚合,从上往下找
set me up
在helm客户端配置helm仓库
helm repo add helm http://localhost:8081/artifactory/helm --username admin --password Xxx
deploy 上传
resolve 提供下载给别人用

推荐使用3.0部署
helm repo ls

从源码部署
helm install -f values.yaml notebook ./

打包chart,上传chart到jcr
cd charts/
helm package notebook
curl -uadmin:passw0rd -T ~/code/notebook-k8s/kube-depoly/charts/notebook-0.1.1.tgz "http://localhost:8081/artifactory/helm/notebook-0.1.1.tgz"
helm search repo notebook

本地更新 
helm repo update

提供拉取使用
helm install notebook helm/notebook

使用helm进行应用的升级和回滚
修改版本,修改副本数,打包
上传到jcr
helm search repo notebook
指定更新版本
helm upgrade notebook helm/notebook --version 0.2.0
helm ls
helm rollback notebook 1

编写notebook应用新功能关联lira需求并运行在本地测试环境
使用jira
提交代码到master

在jenkins流水线进行打包代码扫描镜像构建
dockerfile
推送到本地jcr

不集成YAPI

在jenkins里将该镜像上传到JCR并部署到k8s的测试环境空间
在jenkins中触发流水线
上传notebook的镜像,和chart到jcr
通过helm install 部署notebook等多个服务
登录k8s查看状态

jenkins触发接口自动化测试
在YAPI中创建容器dev环境

在jenkins中对该docker镜像晋级到prod仓库
jenkins 打生产环境的包推送到制品库

在jenkins里将该镜像部署到k8s的生产环境空间
修改脚本,不同命名空间


docker 可视化
docker volume create portainer_data
docker run --name portainer -d -p 8000:8000 -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer

k8s可视化
kubeview

docker pull ghcr.io/benc-uk/kubeview:latest

# 添加仓库
helm repo add kubeview https://benc-uk.github.io/kubeview/charts
# 下载kubeview到本地
helm pull kubeview/kubeview
# 解压下载的kubeview
tar -zxvf kubeview-0.1.20.tgz
# 根据需要修改values.yaml文件
vim kubeview/valus.yaml
# 启动kubeview
helm install kubeview kubeview/kubeview -f kubeview/valus.yaml

rancher
容器管理

你可能感兴趣的:(架构,工程化,运维,云原生)