Kubernetes学习笔记
K8S集群服务搭建环境准备机器环境依赖环境docker部署kubeadm(一键安装k8s) 集群安装依赖镜像k8s部署flannel插件节点Join节点运行 kubectl 出错 私有仓库环境准备安装Compose安装harbor准备工作安装配置伪造证书安装上传镜像进行上传测试 实战演练Kubernetes基本指令基础操作命令手册 K8S实战服务如何部署?服务如何实现扩容和自愈?服务如何实现更新?服务如何实现负载均衡?DNS是否可以解析服务名称?外网如何访问内部服务?K8S集群服务搭建
环境准备
机器环境
节点CPU核数必须是 大于等于 2核,否则k8s无法启动。内存环境准备:不小于 2GB。DNS网络:最好设置为本地网络连通的DNS,否则网络不通,无法下载一些镜像。linux内核:linux内核建议是 4 版本以上,因此需要把linux核心进行升级。4 版本以下也能安装,但是正式线上环境可能会出现问题。查看CPUx相关信息的命令如下:# 查看CPU信息(型号)[root@centos112 ~]# cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c2 Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz# 查看物理CPU个数[root@centos108 ~]# cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l2# 查看每个物理CPU中core的个数(即核数)[root@centos108 ~]# cat /proc/cpuinfo| grep "cpu cores"| uniqcpu cores: 1# 查看逻辑CPU的个数[root@centos108 ~]# cat /proc/cpuinfo| grep "processor"| wc -l2
准备三台虚拟机环境,或者是三台阿里云服务器,这里演示在VMware虚拟机中进行安装。
192.168.254.108: k8s-master01 此机器用来安装k8s master节点的环境192.168.254.110: k8s-node01 此机器用来安装k8s node节点的环境192.168.254.112: k8s-node02 此机器用来安装k8s node节点的环境
依赖环境
配置 IP host 映射关系:# vim /etc/hosts192.168.254.108 k8s-master01192.168.254.110 k8s-node01192.168.254.112 k8s-node02
安装依赖环境:
yum install -y conntrack ntpdate ntp ipvsadm ipset jq iptables curl sysstat libseccomp wget vim net-tools git iproute lrzsz bash-completion tree bridge- utils unzip bind-utils gcc
安装iptables,启动iptables,设置开机自启,清空iptables规则,保存当前规则到默认规则:
# 关闭防火墙systemctl stop firewalld && systemctl disable firewalld# 置空iptablesyum -y install iptables-services && systemctl start iptables && systemctl enable iptables && iptables -F && service iptables save
关闭selinux:
# 闭swap分区【虚拟内存】并且永久关闭虚拟内存swapoff -a && sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab# 关闭selinuxsetenforce 0 && sed -i 's/^SELINUX=.*/SELINUX=disabled/' /etc/selinux/config
升级Linux内核版本:
# 下载升级包rpm -Uvh /elrepo-release-7.0-4.el7.elrepo.noarch.rpm# 安装内核yum --enablerepo=elrepo-kernel install -y kernel-lt# 设置开机从新内核启动grub2-set-default 'CentOS Linux (4.4.189-1.el7.elrepo.x86_64) 7 (Core)'# 注意:设置完内核后,需要重启服务器才会生效。# 查询内核uname -r
调整内核参数,主要正对于k8s:
cat > kubernetes.conf <<EOFnet.bridge.bridge-nf-call-iptables=1net.bridge.bridge-nf-call-ip6tables=1net.ipv4.ip_forward=1vm.swappiness=0vm.overcommit_memory=1vm.panic_on_oom=0fs.inotify.max_user_instances=8192fs.inotify.max_user_watches=1048576fs.file-max=52706963fs.nr_open=52706963net.ipv6.conf.all.disable_ipv6=filter.nf_conntrack_max=2310720EOF# 将优化内核文件拷贝到/etc/sysctl.d/文件夹下,这样优化文件开机的时候能够被调用cp kubernetes.conf /etc/sysctl.d/kubernetes.conf# 手动刷新,让优化文件立即生效sysctl -p /etc/sysctl.d/kubernetes.conf
调整系统临时区:如果已经设置时区,可略过
#设置系统时区为中国/上海timedatectl set-timezone Asia/Shanghai # 将当前的 UTC 时间写入硬件时钟timedatectl set-local-rtc 0 # 重启依赖于系统时间的服务 systemctl restart rsyslog systemctl restart crond
关闭系统不需要的服务:
systemctl stop postfix && systemctl disable postfix
设置日志保存方式:
# 创建保存日志的目录mkdir /var/log/journal# 创建配置文件存放目录mkdir /etc/systemd/journald.conf.d# 创建配置文件cat > /etc/systemd/journald.conf.d/99-prophet.conf <<EOF[Journal]Storage=persistentCompress=yesSyncIntervalSec=5mRateLimitInterval=30sRateLimitBurst=1000SystemMaxUse=10GSystemMaxFileSize=200MMaxRetentionSec=2weekForwardToSyslog=noEOF# 重启systemd journald的配置systemctl restart systemd-journald
打开文件数调整 (可忽略,不执行):
echo "* soft nofile 65536" >> /etc/security/limits.confecho "* hard nofile 65536" >> /etc/security/limits.conf
kube-proxy 开启 ipvs 前置条件:
modprobe br_netfiltercat > /etc/sysconfig/modules/ipvs.modules <<EOF#!/bin/bashmodprobe -- ip_vsmodprobe -- ip_vs_rrmodprobe -- ip_vs_wrrmodprobe -- ip_vs_shmodprobe -- nf_conntrackEOF# 使用lsmod命令查看这些文件是否被引导chmod 755 /etc/sysconfig/modules/ipvs.modules && bash /etc/sysconfig/modules/ipvs.modules && lsmod | grep -e ip_vs -e nf_conntrack
docker部署
安装dockeryum install -y yum-utils device-mapper-persistent-data lvm2# 紧接着配置一个稳定(stable)的仓库、仓库配置会保存到/etc/yum.repos.d/docker-ce.repo文件中yum-config-manager --add-repo /linux/centos/docker-ce.repo# 更新Yum安装的相关Docke软件包&安装Docker CEyum update -y && yum install docker-ce# 安装好后查看版本docker --version 或 docker -v
设置docker daemon文件:
# 创建/etc/docker目录mkdir /etc/docker# 更新daemon.json文件cat > /etc/docker/daemon.json <<EOF{"exec-opts": ["native.cgroupdriver=systemd"],"log-driver": "json-file","log-opts": {"max-size": "100m"}}EOF# 注意: 一定注意编码问题,出现错误:查看命令:journalctl -amu docker 即可发现错误# 创建,存储docker配置文件mkdir -p /etc/systemd/system/docker.service.d
重启docker服务:
systemctl daemon-reload && systemctl restart docker && systemctl enable docker
检测是否按照成功:
[root@centos108 ~]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZE
kubeadm(一键安装k8s)
安装kubernetes的时候,需要安装kubelet, kubeadm等包,但k8s官网给的yum源是 packages.,国内访问不了,此时我们可以使用阿里云的yum仓库镜像。cat > /etc/yum.repos.d/kubernetes.repo <<EOF[kubernetes]name=Kubernetesbaseurl=/kubernetes/yum/repos/kubernetes-el7-x86_64enabled=1gpgcheck=0repo_gpgcheck=0gpgkey=/kubernetes/yum/doc/yum-key.gpg/kubernetes/yum/doc/rpm-package-key.gpgEOF
安装kubeadm、kubelet、kubectl:
yum install -y kubeadm-1.15.1 kubelet-1.15.1 kubectl-1.15.1# 启动 kubeletsystemctl enable kubelet && systemctl start kubelet
查看版本:
kubectl version
集群安装
依赖镜像
查看需要安装的镜像包:# kubeadm config images listk8s.gcr.io/kube-apiserver:v1.15.1k8s.gcr.io/kube-controller-manager:v1.15.1k8s.gcr.io/kube-scheduler:v1.15.1k8s.gcr.io/kube-proxy:v1.15.1k8s.gcr.io/pause:3.1k8s.gcr.io/etcd:3.3.10k8s.gcr.io/coredns:1.3.1
提前在本地下载以上镜像,压缩打包发到虚拟机中,并解压到本地镜像仓库 编写脚本文件,导入镜像包到本地 docker 镜像仓库:kubeadm 初始化k8s集群的时候,会从gce Google云中下载(pull)相应的镜像,且镜像相对比较大,下载比较慢,且需要解决科学上网的一个问题,国内上goole,懂得…导入镜像脚本代码 (在任意目录下创建sh脚本文件:image-load.sh)
#!/bin/bash# 注意: 镜像解压的目录位置ls /usr/apps/kubeadm-basic.images > /tmp/images-list.txtcd /usr/apps/kubeadm-basic.imagesfor i in $(cat /tmp/images-list.txt)dodocker load -i $idonerm -rf /tmp/images-list.txt
修改权限,可执行权限,并开始执行镜像导入
chmod 755 image-load.sh```bash./image-load.sh
传输文件到其他node节点:
# 拷贝到node01节点scp -r image-load.sh root@k8s-node01:/usr/apps/kubeadm-basic.images/# 贝到node02节点scp -r image-load.sh root@k8s-node02:/usr/apps/kubeadm-basic.images/# 其他节点依次执行sh脚本,导入镜像
导入成功后镜像仓库如下图:
k8s部署
注意:初始化主节点,只需要在主节点执行拉取 yaml 资源配置文件kubeadm config print init-defaults > kubeadm-config.yaml
修改yaml资源文件: 初始化主节点,开始部署:
kubeadm init --config=kubeadm-config.yaml --experimental-upload-certs | tee kubeadm-init.log
注意:执行此命令,CPU核心数量必须大于1核,否则无法执行成功。kubernetes主节点初始化成功后,如下所示: 按照k8s指示,执行下面的命令:初始化成功后执行如下命令
# 创建目录,保存连接配置缓存,认证文件mkdir -p $HOME/.kube# 拷贝集群管理配置文件sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config# 授权给配置文件sudo chown $(id -u):$(id -g) $HOME/.kube/config
执行命令后查询node:
[root@centos108 kubeadm-basic.images]# kubectl get nodeNAME STATUSROLES AGEVERSIONcentos108 NotReady master 5m40s v1.15.1
我们发现已经可以成功查询node节点信息了,但是节点的状态却是NotReady,不是Runing的状态。原因是此时我们使用ipvs+flannel的方式进行网络通信,但是flannel网络插件还没有部署,因此节点状态此时为NotReady。
flannel插件
网络拓扑图:注意:部署flannel网络插件,只需要在主节点执行。下载flannel网络插件:wget /coreos/flannel/master/Documentation/kube-flannel.yml
部署flannel:
kubectl create -f kube-flannel.yml# 也可进行部署网络kubectl apply -f /coreos/flannel/master/Documentation/kube-flannel.yml
部署完毕查询pod,现一些异常错误现象:
kubectl get pod -n kube-system
发现通过flannel部署的pod都出现pending,ImagePullBackOff这样的问题,查询日志信息,发现了一些错误:
# 查询一个pod的详细信息kubectl describe pod kube-flannel-ds-amd64-rd2wt -n kube-system
部署flannel网络插件时候,注意网络连通的问题,可以先去到 github 进行下载:/coreos/flannel/releases
docker load < flanneld-v0.12.0-amd64.docker
再次查看 node,发现节点状态已经是 Ready,说明网络组件 flannel 已经部署成功:
[root@centos108 flannel]# kubectl get nodeNAME STATUS ROLES AGE VERSIONcentos108 Ready master 32h v1.15.1
节点Join
构建kubernetes主节点成功,会产生一个日志文件(命令中指定日志输出文件 “kubeadm-init.log”),内容如下所示:tail -50 /usr/apps/kubeadm-basic.images/kubeadm-init.log
加入主节点以及其余工作节点,执行安装日志中的命令即可:
# 复制命令到其他几个node节点进行执行即可kubeadm join 192.168.254.108:6443 --token abcdef.0123456789abcdef \--discovery-token-ca-cert-hash sha256:2d71bf5f36489d839b1588ded2f2fa1ef71262a7b45318dc32e16c56935dd931
可能会出现如下问题:token 过期 于是可以使用如下命令在 master 节点执行,重新创建token:
[root@centos108 flannel]# kubeadm token create2jxq79.edxxq13zrmf299zd
检查token是否已过期,可以使用如下命令:
kubeadm token list
重新复制如下命令到其他几个node节点再次进行执行即可
kubeadm join 192.168.254.108:6443 --token 2jxq79.edxxq13zrmf299zd \--discovery-token-ca-cert-hash sha256:2d71bf5f36489d839b1588ded2f2fa1ef71262a7b45318dc32e16c56935dd931
执行完毕,在 master 节点查看效果如下所示:发现还有一些节点处于NotReady状态,是因为这些节点pod容器还处于初始化的状态,需要等一点时间 更详细查看命令,可以看见初始化节点所属节点:
# 查询工作空间中pod容器的详细信息kubectl get pod -n kube-system -o wide
节点运行 kubectl 出错
The connection to the server localhost:8080 was refused - did you specify the right host or port?
出现这个问题的原因是kubectl命令需要使用kubernetes-admin来运行解决办法:将主节点(master节点)中的【/etc/kubernetes/admin.conf】文件拷贝到从节点相同目录下 配置环境变量:
echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bash_profile# 立即生效source ~/.bash_profile
私有仓库
搭建私有仓库 harbor:harbor私有仓库和 Registry 私有仓库相比较而言,功能强大很多,并且支持 web 图形化管理,推荐使用。环境准备
Python应该是 2.7 或更高版本Docker引擎应为1.10或更高版本:Docker环境的安装前面已有,这里不再赘述Docker Compose需要为1.6.0或更高版本安装Compose
官网地址:/docker/compose/releases,选择自己需要安装的版本 在线下载 docker-compose,harbor 需要借助 docker-compose 安装# 安装依赖包yum install -y yum-utils device-mapper-persistent-data lvm2curl -L /docker/compose/releases/download/1.27.4/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
授权:
chmod u+x /usr/local/bin/docker-compose# 查看其版本信息docker-compose -version
安装harbor
github官方地址:/goharbor/harbor/releases准备工作
追加 ip:hostname 到每一台机器节点echo "192.168.254.116 " >> /etc/hosts
安装配置
解压缩安装包:tar -zxvf arbor-offline-installer-<version>.tgz -C /Volumes/D/tools/
配置 harbor.cfg:
hostname:目标的主机名或者完全限定域名ui_url_protocol:http 或 https。 默认为 httpdb_password:用于 db_auth的 MySQL数据库的根密码。更改此密码进行任何生产用途max_job_workers:(默认值为3)作业服务中的复制工作人员的最大数量。对于每个映像复制作业,工作人员将存储库的所有标签同步到远程目标。增加此数字允许系统中更多的并发复制作业。但是,由于每个工作人员都会消耗一定数量的网络/ CPU / IO资源,请根据主机的硬件资源,仔细选择该属性的值customize_crt:( on或 off。默认为 on)当此属性打开时, prepare脚本将为注册表的令牌的生成 /验证创建私钥和根证书ssl_cert:SSL证书的路径,仅当协议设置为https时才应用ssl_cert_key:SSL密钥的路径,仅当协议设置为https时才应用secretkey_path:用于在复制策略中加密或解密远程注册表的密码的密钥路径
伪造证书
创建 https 证书以及配置相关目录权限:# 生成证书私钥openssl genrsa -des3 -out server.key 2048# 证书服务openssl req -new -key server.key -out server.csr
继续:
# 备份私钥cp server.key # 转换为证书openssl rsa -in -out server.key# 给证书签名openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt# 给所有证书授权chmod 755 *
安装
运行脚本进行安装:./install.sh
访问测试:/。 登录:默认管理员用户名/密码为admin / Harbor12345
上传镜像进行上传测试
指定镜像仓库地址vim /etc/docker/daemon.json"insecure-registries": [""]# 把证书添加到 /etc/docker/daemon.json 文件中,其中的每一个节点都做如下模式添加: 伪造证书{"exec-opts": ["native.cgroupdriver=systemd"],"log-driver": "json-file","log-opts": {"max-size": "100m"},"insecure-registries": [""]}# node01 添加 "insecure-registries": [""]# node02 添加 "insecure-registries": [""]
重启 docker-compose:
[root@centos116 harbor]# docker-compose restartRestarting harbor-jobservice ... doneRestarting nginx ... doneRestarting harbor-ui... doneRestarting harbor-adminserver ... doneRestarting harbor-db... doneRestarting registry ... doneRestarting harbor-log ... done
重启各个node结点的docker:
systemctl restart docker
上传镜像到私有仓库:
# 下载测试镜像docker pull hello-world# 给镜像重新打标签docker tag hello-world /hello-world:latest# 登录进行上传docker login Username: adminPassword:# 上传镜像docker push /hello-world:latest
push不成功:原因是没有指定项目
received unexpected HTTP status: 500 Internal Server Error
进入到 harbor 管理界面新建项目test
,然后重新打 tag 再 push 镜像
docker tag hello-world /test/hello-world:latestdocker push /test/hello-world:latest
实战演练
Kubernetes基本指令
基础操作
# 创建并运行一个pod:deployment、rs、pod被自动创建kubectl run my-nginx --image=nginx --port=80# 增加创建副本数量kubectl scale deployment/my-nginx --replicas = 3# 添加service:kubectl expose将RC、Service、Deployment或Pod作为新的Kubernetes Service公开。kubectl expose deployment/my-nginx --port=30000 --target-port=80# 编辑service配置文件kubectl edit svc/my-nginx# 其他的基础指令# 查看集群中有几个Nodekubectl get nodes# 查看podkubectl get pod# 查看服务详情信息kubectl describe pod my-nginx-379829228-cwlbb# 查看deployment对象kubectl get deployments# 查看ReplicaSet对象kubectl get rs# 查看日志kubectl logs my-nginx# 登录 pod 内部容器kubectl exec -it my-nginx -sh# 删除podkubectl delete pod my-nginx-379829228-cwlbb# 删除部署的my-nginx服务。彻底删除pod$ kubectl delete deployment my-nginxdeployment "my-nginx" deleted# 删除service服务kubectl delete service my-nginx
查看帮助文档:
kubectl --help# 进一步查看指令的帮助文档kubectl 指令名称 --help
命令手册
K8S实战
服务如何部署?
指令:kubectl run myapp --image=/springboot/00-primary-start:1.0 --port=8080
查看 pod,结果出现了问题: 想查看更多信息,可以 describe 这个失败的 Pod:
kubectl describe pod myapp-65c95b5dd-sscm9
显示错误:Failed to pull image "/springboot/00-primary-start:1.0"
除了网络连接问题外,还有三个主要元凶: 镜像 tag 不正确镜像不存在(或者是在另一个仓库)Kubernetes 没有权限去拉那个镜像 使用 docker pull 命令拉取镜像成功,那么很可能 Kubernetes 没有权限去拉取这个镜像。那么参考镜像拉取 Secrets 来解决这个问题。用 docker 登录私有仓库 harbor 后,会生成~/.docker/config.json文件,config.json文件内容如下:
{"auths": {"": {"auth": "YWRtaW46SGFyYm9yMTIzNDU="}}}
再对上面的config.json进行base64加密,命令如下:
[root@centos108 ~]# cat ~/.docker/config.json | base64 -w 0ewoJImF1dGhzIjogewoJCSJodWIudmVsaS5jb20iOiB7CgkJCSJhdXRoIjogIllXUnRhVzQ2U0dGeVltOXlNVEl6TkRVPSIKCQl9Cgl9Cn0K
创建secret.yaml文件,文件内容如下:
apiVersion: v1kind: Secretmetadata:name: mysecretdata:.dockerconfigjson: ewoJImF1dGhzIjogewoJCSJodWIudmVsaS5jb20iOiB7CgkJCSJhdXRoIjogIllXUnRhVzQ2U0dGeVltOXlNVEl6TkRVPSIKCQl9Cgl9Cn0Ktype: kubernetes.io/dockerconfigjson
创建secret,命令如下:
kubectl create -f secret.yaml
接下来就可以进行服务部署了:
# 方式一kubectl run myapp --image=/springboot/00-primary-start:1.0 --port=8080# 方式二kubectl create deployment myapp --image=/springboot/00-primary-start:1.0
查看并访问之也是OK的: 也可以通过 yaml 文件方式部署Pod或者Deployment:新建pod,用imagePullSecrets指定secret,pod的yaml文件示例如下:
# vim primary-start-pod.yamlapiVersion: v1kind: Pod # 或 Deploymentmetadata:name: myappspec:containers:- name: myappimage: /springboot/00-primary-start:1.0imagePullPolicy: AlwaysimagePullSecrets:- name: mysecret
创建 pod,命令如下:
kubectl create -f primary-start-pod.yaml
服务如何实现扩容和自愈?
指令:kubectl scale deployment myapp --replicas=3
查看发现扩容三个副本成功了。服务如何实现自愈:删除一个 pod,或是删除所有的 pod,观察 pod 副本数量是否和预期设定的数量(3 个) 。 可以看到删除一个服务后,副本控制器会对服务进行重建工作,会保证服务数量与预期设定的数量一致。及时是全部删掉,副本控制器也会去自动帮助我们创建设定数量的POD。 问题:删除 POD 肯定删除不了服务的,那么如何删除服务?答案:删除 RS 或者 Deployment,就可以删除所有的 Deployment、RS 对应的服务。
服务如何实现更新?
需求:进行版本迭代,发不了新的版本,新的服务需要上线,如何实现服务滚动更新?指令:kubectl set image deployment/myapp myapp=/springboot/00-primary-start:2.0
服务如何实现负载均衡?
K8S 提供资源对象 Service,由这个 service 实现下面 pod 的负载均衡,通过 service 访问 pod。 创建一个 service,由 Sevice 实现负载均衡,指令如下:kubectl expose deployment myapp --target-port=8080 --port=88
查看:Session Affinity 可以指定为 ClientIP 或者 None使用的什么负载均衡策略呢?
kubectl describe service myapp
默认是根据 kube-proxy 的负载均衡策略:随机策略。
DNS是否可以解析服务名称?
在集群构建的时候,已经安装好了 dns 服务,因此可以利用 dns 解析服务名称,实现服务通信: 这里的 DNS 就类似于原来微服务的注册中心。实验:登录 pod 内部容器,在容器内部 ping service 服务名称,看是否可以 ping 通。首先看下 dns 是否已经搭建:可以看到是有的,在前面搭建集群过程中已经搭建好了。 验证 DNS 是否OK?# 进入pod容器中kubectl exec -it {POD-NAME} -- sh
结果发现 ping 不通,如何解决? ---- 需要使用 ipvs 替换 iptables,操作是在所有节点上
# 开启内核支持$ vim /etc/sysctl.confnet.ipv4.ip_forward = 1net.bridge.bridge-nf-call-iptables = 1net.bridge.bridge-nf-call-ip6tables = 1$ sysctl -p# 开启ipvs支持$ cat /etc/sysconfig/modules/ipvs.modules#!/bin/bashmodprobe -- ip_vsmodprobe -- ip_vs_rrmodprobe -- ip_vs_wrrmodprobe -- ip_vs_shmodprobe -- nf_conntrack# 配置kube-proxy,在master上操作,因使用kubeadmin安装,所以操作方式如下kubectl edit cm kube-proxy -n kube-systemconfigmap/kube-proxy edited
在master重启kube-proxy:
kubectl get pod -n kube-system | grep kube-proxy | awk '{print $1}' | xargs kubectl delete pod -n kube-system
验证ipvs是否开启: 这时再进入 pod 容器 ping 一下服务名就好使了: 注意:这时的负载均衡策略已经变为 ipvs 的轮询策略了
外网如何访问内部服务?
Service IP 类型是 clusterIp,此 IP 类型不能对外网提供服务,因此需要修改 IP 类型为 NodePort,然后才能通过外网访问。修改指令:kubectl edit svc myapp
修改为 NodePort 类型后,再次查看Service,这个时候就可以通过宿主机IP+映射端口进行外网访问了:
如果觉得《JavaEE 企业级分布式高级架构师(十八)容器虚拟化技术(3)》对你有帮助,请点赞、收藏,并留下你的观点哦!