乐趣区

关于k8s:冰河教你一次性成功安装K8S集群基于一主两从模式

写在后面

钻研 K8S 有一段时间了,最开始学习 K8S 时,依据网上的教程装置 K8S 环境总是报错。所以,我就扭转了学习策略,先不搞环境搭建了。先通过官网学习了 K8S 的整体架构,底层原理,又硬啃了一遍 K8S 源码。别问我为哈这样学,只是我感觉对我集体来说,这样学能让我更好的了解整套云原生体系。这不,这次,我总结了如何一次性胜利装置 K8S 集群的办法。咱们明天先来说说如何基于一主两从模式搭建 K8S 集群。前面,咱们再上如何齐全无坑搭建 K8S 高可用集群的计划。

文章和搭建环境所须要的 yml 文件已收录到:https://github.com/sunshinelyz/technology-binghe 和 https://gitee.com/binghe001/technology-binghe。如果文件对你有点帮忙,别忘记给个 Star 哦!

集群布局

IP 主机名 节点 操作系统版本
192.168.175.101 binghe101 Master CentOS 8.0.1905
192.168.175.102 binghe102 Worker CentOS 8.0.1905
192.168.175.103 binghe103 Worker CentOS 8.0.1905

根底配置

在三台服务器上的 /etc/hosts 文件中增加如下配置项。

192.168.175.101  binghe101
192.168.175.102  binghe102
192.168.175.103  binghe103

查看零碎环境

别离在三台服务器上查看零碎的环境。

1. 查看服务器操作系统版本

cat /etc/redhat-release

装置 Docker 和 K8S 集群的服务器操作系统版本须要在 CentOS 7 以上。

2. 查看服务器的主机名

hostname

留神:集群中服务器的主机名不能是 localhost。

3. 查看服务器的 CPU 核数

lscpu

留神:集群中服务器的 CPU 核数不能少于 2 个。

4. 查看服务器网络

以 binghe101(Master)服务器为例。在服务器上执行 ip route show 命令来查看服务器的默认网卡,如下所示。

[root@binghe101 ~]# ip route show
default via 192.168.175.2 dev ens33 proto static metric 100 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown 
192.168.175.0/24 dev ens33 proto kernel scope link src 192.168.175.101 metric 100 

在下面的输入信息中有如下一行标注了 binghe101 服务器所应用的默认网卡。

default via 192.168.175.2 dev ens33 proto static metric 100 

能够看到,binghe101 服务器应用的默认网卡为 ens33。

接下来,应用 ip address 命令查看服务器的 IP 地址,如下所示。

[root@binghe101 ~]# ip address
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:0c:29:68:06:63 brd ff:ff:ff:ff:ff:ff
    inet 192.168.175.101/24 brd 192.168.175.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::890f:5a92:4171:2a11/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

能够看到,binghe101 服务器上的默认网卡的 IP 地址为192.168.175.101,K8S 将应用此 IP 地址与集群内的其余节点通信。集群中所有 K8S 所应用的 IP 地址必须能够互通。

Docker 装置

别离在三台服务器上安装 Docker 并配置阿里云镜像加速器。

1. 装置 Docker

新建 auto_install_docker.sh 脚本文件

vim auto_install_docker.sh

文件的内容如下所示。

export REGISTRY_MIRROR=https://registry.cn-hangzhou.aliyuncs.com
dnf install yum*
yum install -y yum-utils  device-mapper-persistent-data  lvm2
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
dnf install https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.13-3.1.el7.x86_64.rpm
yum install docker-ce docker-ce-cli -y
systemctl enable docker.service
systemctl start docker.service
docker version

或者指定 Docker 的版本进行装置,此时 auto_install_docker.sh 脚本文件的内容如下所示。

export REGISTRY_MIRROR=https://registry.cn-hangzhou.aliyuncs.com
dnf install yum*
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install -y docker-ce-19.03.8 docker-ce-cli-19.03.8 containerd.io
systemctl enable docker.service
systemctl start docker.service
docker version

应用如下命令赋予 auto_install_docker.sh 文件可执行权限。

chmod a+x ./auto_install_docker.sh

接下来,间接运行 auto_install_docker.sh 脚本文件装置 Docker 即可。

./auto_install_docker.sh

2. 配置阿里云镜像加速器

新建脚本文件 aliyun_docker_images.sh。

vim aliyun_docker_images.sh

文件内容如下所示。

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

为 aliyun_docker_images.sh 脚本文件赋予可执行权限,如下所示。

chmod a+x ./aliyun_docker_images.sh

执行 aliyun_docker_images.sh 脚本文件配置阿里云镜像加速器。

./aliyun_docker_images.sh

零碎设置

别离在三台服务器上进行零碎设置。

1. 装置 nfs-utils

yum install -y nfs-utils
yum install -y wget

2. 敞开防火墙

systemctl stop firewalld
systemctl disable firewalld

3. 敞开 SeLinux

setenforce 0
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config

4. 敞开 swap

swapoff -a
yes | cp /etc/fstab /etc/fstab_bak
cat /etc/fstab_bak |grep -v swap > /etc/fstab

5. 批改 /etc/sysctl.conf

新建 sys_config.sh 脚本文件。

vim sys_config.sh

sys_config.sh 脚本文件的内容如下所示,

# 如果有配置,则批改
sed -i "s#^net.ipv4.ip_forward.*#net.ipv4.ip_forward=1#g"  /etc/sysctl.conf
sed -i "s#^net.bridge.bridge-nf-call-ip6tables.*#net.bridge.bridge-nf-call-ip6tables=1#g"  /etc/sysctl.conf
sed -i "s#^net.bridge.bridge-nf-call-iptables.*#net.bridge.bridge-nf-call-iptables=1#g"  /etc/sysctl.conf
sed -i "s#^net.ipv6.conf.all.disable_ipv6.*#net.ipv6.conf.all.disable_ipv6=1#g"  /etc/sysctl.conf
sed -i "s#^net.ipv6.conf.default.disable_ipv6.*#net.ipv6.conf.default.disable_ipv6=1#g"  /etc/sysctl.conf
sed -i "s#^net.ipv6.conf.lo.disable_ipv6.*#net.ipv6.conf.lo.disable_ipv6=1#g"  /etc/sysctl.conf
sed -i "s#^net.ipv6.conf.all.forwarding.*#net.ipv6.conf.all.forwarding=1#g"  /etc/sysctl.conf
# 可能没有,追加
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
echo "net.bridge.bridge-nf-call-ip6tables = 1" >> /etc/sysctl.conf
echo "net.bridge.bridge-nf-call-iptables = 1" >> /etc/sysctl.conf
echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf
echo "net.ipv6.conf.default.disable_ipv6 = 1" >> /etc/sysctl.conf
echo "net.ipv6.conf.lo.disable_ipv6 = 1" >> /etc/sysctl.conf
echo "net.ipv6.conf.all.forwarding = 1"  >> /etc/sysctl.conf
# 执行命令以利用
sysctl -p

执行如下命令赋予 sys_config.sh 文件可执行权限。

chmod a+x ./sys_config.sh

执行 sys_config.sh 脚本文件。

./sys_config.sh

装置 K8S

别离在三台服务器上安装 K8S。

1. 配置 K8S yum 源

新建 k8s_yum.sh 脚本文件。

vim k8s_yum.sh

文件的内容如下所示。

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
       http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

赋予 k8s_yum.sh 脚本文件的可执行权限。

chmod a+x ./k8s_yum.sh

执行 k8s_yum.sh 文件。

./k8s_yum.sh

2. 卸载旧版本的 K8S

yum remove -y kubelet kubeadm kubectl

3. 装置 kubelet、kubeadm、kubectl

yum install -y kubelet-1.18.2 kubeadm-1.18.2 kubectl-1.18.2

4. 批改 docker Cgroup Driver 为 systemd

sed -i "s#^ExecStart=/usr/bin/dockerd.*#ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --exec-opt native.cgroupdriver=systemd#g" /usr/lib/systemd/system/docker.service

5. 重启 docker,并启动 kubelet

systemctl daemon-reload
systemctl restart docker
systemctl enable kubelet && systemctl start kubelet

综合装置脚本

综上,上述装置 Docker、进行零碎设置,装置 K8S 的操作能够对立成 auto_install_docker_k8s.sh 脚本。脚本的内容如下所示。

# 装置 Docker 19.03.8
export REGISTRY_MIRROR=https://registry.cn-hangzhou.aliyuncs.com
dnf install yum*
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install -y docker-ce-19.03.8 docker-ce-cli-19.03.8 containerd.io
systemctl enable docker.service
systemctl start docker.service
docker version

#配置阿里云镜像加速器
mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF'
{"registry-mirrors": ["https://zz3sblpi.mirror.aliyuncs.com"]
}
EOF
systemctl daemon-reload
systemctl restart docker

#装置 nfs-utils
yum install -y nfs-utils
yum install -y wget

#敞开防火墙
systemctl stop firewalld
systemctl disable firewalld

#敞开 SeLinux
setenforce 0
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config

# 敞开 swap
swapoff -a
yes | cp /etc/fstab /etc/fstab_bak
cat /etc/fstab_bak |grep -v swap > /etc/fstab

#批改 /etc/sysctl.conf
# 如果有配置,则批改
sed -i "s#^net.ipv4.ip_forward.*#net.ipv4.ip_forward=1#g"  /etc/sysctl.conf
sed -i "s#^net.bridge.bridge-nf-call-ip6tables.*#net.bridge.bridge-nf-call-ip6tables=1#g"  /etc/sysctl.conf
sed -i "s#^net.bridge.bridge-nf-call-iptables.*#net.bridge.bridge-nf-call-iptables=1#g"  /etc/sysctl.conf
sed -i "s#^net.ipv6.conf.all.disable_ipv6.*#net.ipv6.conf.all.disable_ipv6=1#g"  /etc/sysctl.conf
sed -i "s#^net.ipv6.conf.default.disable_ipv6.*#net.ipv6.conf.default.disable_ipv6=1#g"  /etc/sysctl.conf
sed -i "s#^net.ipv6.conf.lo.disable_ipv6.*#net.ipv6.conf.lo.disable_ipv6=1#g"  /etc/sysctl.conf
sed -i "s#^net.ipv6.conf.all.forwarding.*#net.ipv6.conf.all.forwarding=1#g"  /etc/sysctl.conf
# 可能没有,追加
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
echo "net.bridge.bridge-nf-call-ip6tables = 1" >> /etc/sysctl.conf
echo "net.bridge.bridge-nf-call-iptables = 1" >> /etc/sysctl.conf
echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf
echo "net.ipv6.conf.default.disable_ipv6 = 1" >> /etc/sysctl.conf
echo "net.ipv6.conf.lo.disable_ipv6 = 1" >> /etc/sysctl.conf
echo "net.ipv6.conf.all.forwarding = 1"  >> /etc/sysctl.conf
# 执行命令以利用
sysctl -p

# 配置 K8S 的 yum 源
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=http://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=http://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg
       http://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

# 卸载旧版本 K8S
yum remove -y kubelet kubeadm kubectl

# 装置 kubelet、kubeadm、kubectl,这里我装置的是 1.18.2 版本,你也能够装置 1.17.2 版本
yum install -y kubelet-1.18.2 kubeadm-1.18.2 kubectl-1.18.2

# 批改 docker Cgroup Driver 为 systemd
# # 将 /usr/lib/systemd/system/docker.service 文件中的这一行 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
# # 批改为 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --exec-opt native.cgroupdriver=systemd
# 如果不批改,在增加 worker 节点时可能会碰到如下谬误
# [WARNING IsDockerSystemdCheck]: detected "cgroupfs" as the Docker cgroup driver. The recommended driver is "systemd". 
# Please follow the guide at https://kubernetes.io/docs/setup/cri/
sed -i "s#^ExecStart=/usr/bin/dockerd.*#ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --exec-opt native.cgroupdriver=systemd#g" /usr/lib/systemd/system/docker.service

# 设置 docker 镜像,进步 docker 镜像下载速度和稳定性
# 如果您拜访 https://hub.docker.io 速度十分稳固,亦能够跳过这个步骤
# curl -sSL https://kuboard.cn/install-script/set_mirror.sh | sh -s ${REGISTRY_MIRROR}

# 重启 docker,并启动 kubelet
systemctl daemon-reload
systemctl restart docker
systemctl enable kubelet && systemctl start kubelet

docker version

留神:我装置的 K8S 版本是 1.18.2,大家在装置 K8S 时,也能够抉择其余版本进行装置

赋予 auto_install_docker_k8s.sh 脚本文件可执行权限。

chmod a+x ./auto_install_docker_k8s.sh

执行 auto_install_docker_k8s.sh 脚本文件。

./auto_install_docker_k8s.sh

留神:须要在每台服务器上执行 auto_install_docker_k8s.sh 脚本文件。

初始化 Master 节点

只在 binghe101 服务器上执行的操作。

1. 初始化 Master 节点的网络环境

# 只在 master 节点执行
# export 命令只在以后 shell 会话中无效,开启新的 shell 窗口后,如果要持续装置过程,请从新执行此处的 export 命令
export MASTER_IP=192.168.175.101
# 替换 k8s.master 为 您想要的 dnsName
export APISERVER_NAME=k8s.master
# Kubernetes 容器组所在的网段,该网段装置实现后,由 kubernetes 创立,当时并不存在于您的物理网络中
export POD_SUBNET=172.18.0.1/16
echo "${MASTER_IP}    ${APISERVER_NAME}" >> /etc/hosts

2. 初始化 Master 节点

在 binghe101 服务器上创立 init_master.sh 脚本文件,文件内容如下所示。

#!/bin/bash
# 脚本出错时终止执行
set -e

if [${#POD_SUBNET} -eq 0 ] || [${#APISERVER_NAME} -eq 0 ]; then
  echo -e "\033[31;1m 请确保您曾经设置了环境变量 POD_SUBNET 和 APISERVER_NAME \033[0m"
  echo 以后 POD_SUBNET=$POD_SUBNET
  echo 以后 APISERVER_NAME=$APISERVER_NAME
  exit 1
fi


# 查看残缺配置选项 https://godoc.org/k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta2
rm -f ./kubeadm-config.yaml
cat <<EOF > ./kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: v1.18.2
imageRepository: registry.cn-hangzhou.aliyuncs.com/google_containers
controlPlaneEndpoint: "${APISERVER_NAME}:6443"
networking:
  serviceSubnet: "10.96.0.0/16"
  podSubnet: "${POD_SUBNET}"
  dnsDomain: "cluster.local"
EOF

# kubeadm init
# 依据您服务器网速的状况,您须要等待 3 - 10 分钟
kubeadm init --config=kubeadm-config.yaml --upload-certs

# 配置 kubectl
rm -rf /root/.kube/
mkdir /root/.kube/
cp -i /etc/kubernetes/admin.conf /root/.kube/config

# 装置 calico 网络插件
# 参考文档 https://docs.projectcalico.org/v3.13/getting-started/kubernetes/self-managed-onprem/onpremises
echo "装置 calico-3.13.1"
rm -f calico-3.13.1.yaml
wget https://kuboard.cn/install-script/calico/calico-3.13.1.yaml
kubectl apply -f calico-3.13.1.yaml

赋予 init_master.sh 脚本文件可执行权限。

chmod a+x ./init_master.sh

执行 init_master.sh 脚本文件。

./init_master.sh

3. 查看 Master 节点的初始化后果

(1)确保所有容器组处于 Running 状态

# 执行如下命令,期待 3-10 分钟,直到所有的容器组处于 Running 状态
watch kubectl get pod -n kube-system -o wide

如下所示。

[root@binghe101 ~]# watch kubectl get pod -n kube-system -o wide
Every 2.0s: kubectl get pod -n kube-system -o wide                                                                                                                          binghe101: Sat May  2 23:40:33 2020

NAME                                       READY   STATUS    RESTARTS   AGE     IP                NODE        NOMINATED NODE   READINESS GATES
calico-kube-controllers-5b8b769fcd-l2tmm   1/1     Running   0          3m59s   172.18.203.67     binghe101   <none>           <none>
calico-node-8krsl                          1/1     Running   0          3m59s   192.168.175.101   binghe101   <none>           <none>
coredns-546565776c-rd2zr                   1/1     Running   0          3m59s   172.18.203.66     binghe101   <none>           <none>
coredns-546565776c-x8r7l                   1/1     Running   0          3m59s   172.18.203.65     binghe101   <none>           <none>
etcd-binghe101                             1/1     Running   0          4m14s   192.168.175.101   binghe101   <none>           <none>
kube-apiserver-binghe101                   1/1     Running   0          4m14s   192.168.175.101   binghe101   <none>           <none>
kube-controller-manager-binghe101          1/1     Running   0          4m14s   192.168.175.101   binghe101   <none>           <none>
kube-proxy-qnffb                           1/1     Running   0          3m59s   192.168.175.101   binghe101   <none>           <none>
kube-scheduler-binghe101                   1/1     Running   0          4m14s   192.168.175.101   binghe101   <none>           <none>

(2)查看 Master 节点初始化后果

kubectl get nodes -o wide

如下所示。

[root@binghe101 ~]# kubectl get nodes -o wide
NAME        STATUS   ROLES    AGE     VERSION   INTERNAL-IP       EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION         CONTAINER-RUNTIME
binghe101   Ready    master   5m43s   v1.18.2   192.168.175.101   <none>        CentOS Linux 8 (Core)   4.18.0-80.el8.x86_64   docker://19.3.8

初始化 Worker 节点

1. 获取 join 命令参数

在 Master 节点上执行如下命令获取 join 命令参数。

kubeadm token create --print-join-command

具体执行如下所示。

[root@binghe101 ~]# kubeadm token create --print-join-command
W0502 23:44:55.218947   59318 configset.go:202] WARNING: kubeadm cannot validate component configs for API groups [kubelet.config.k8s.io kubeproxy.config.k8s.io]
kubeadm join k8s.master:6443 --token s0hoh1.2cwyf1fyyjl2h04a     --discovery-token-ca-cert-hash sha256:6d78e360dc64d84762611ac6beec8ac0f0fe9f72a5c2cca008df949e07827c19

其中,有如下一行输入。

kubeadm join k8s.master:6443 --token s0hoh1.2cwyf1fyyjl2h04a     --discovery-token-ca-cert-hash sha256:6d78e360dc64d84762611ac6beec8ac0f0fe9f72a5c2cca008df949e07827c19

这行代码就是获取到的 join 命令。

留神:join 命令中的 token 的无效工夫为 2 个小时,2 小时内,能够应用此 token 初始化任意数量的 worker 节点。

2. 初始化 Worker 节点

针对所有的 worker 节点执行,在这里,就是在 binghe102 服务器和 binghe103 服务器上执行。

创立 init_worker.sh 脚本文件,文件内容如下所示。

# 只在 worker 节点执行
# 192.168.175.101 为 master 节点的内网 IP
export MASTER_IP=192.168.175.101
# 替换 k8s.master 为初始化 master 节点时所应用的 APISERVER_NAME
export APISERVER_NAME=k8s.master
echo "${MASTER_IP}    ${APISERVER_NAME}" >> /etc/hosts

# 替换为 master 节点上 kubeadm token create 命令输入的 join
kubeadm join k8s.master:6443 --token s0hoh1.2cwyf1fyyjl2h04a     --discovery-token-ca-cert-hash sha256:6d78e360dc64d84762611ac6beec8ac0f0fe9f72a5c2cca008df949e07827c19

其中,kubeadm join… 就是 master 节点上 kubeadm token create 命令输入的 join。

赋予 init_worker.sh 脚本文件文件可执行权限,并执行 init_worker.sh 脚本文件。

chmod a+x ./init_worker.sh
./init_worker.sh

3. 查看初始化后果

在 Master 节点执行如下命令查看初始化后果。

kubectl get nodes -o wide

如下所示。

[root@binghe101 ~]# kubectl get nodes
NAME        STATUS   ROLES    AGE     VERSION
binghe101   Ready    master   20m     v1.18.2
binghe102   Ready    <none>   2m46s   v1.18.2
binghe103   Ready    <none>   2m46s   v1.18.2

留神:kubectl get nodes 命令前面加上 -o wide 参数能够输入更多的信息。

重启 K8S 集群引起的问题

1.Worker 节点故障不能启动

Master 节点的 IP 地址发生变化,导致 worker 节点不能启动。须要重新安装 K8S 集群,并确保所有节点都有固定的内网 IP 地址。

2.Pod 解体或不能失常拜访

重启服务器后应用如下命令查看 Pod 的运行状态。

kubectl get pods --all-namespaces

发现很多 Pod 不在 Running 状态,此时,须要应用如下命令删除运行不失常的 Pod。

kubectl delete pod <pod-name> -n <pod-namespece>

留神:如果 Pod 是应用 Deployment、StatefulSet 等控制器创立的,K8S 将创立新的 Pod 作为代替,重新启动的 Pod 通常可能失常工作。

重磅福利

微信搜一搜【冰河技术】微信公众号,关注这个有深度的程序员,每天浏览超硬核技术干货,公众号内回复【PDF】有我筹备的一线大厂面试材料和我原创的超硬核 PDF 技术文档,以及我为大家精心筹备的多套简历模板(不断更新中),心愿大家都能找到心仪的工作,学习是一条时而郁郁寡欢,时而开怀大笑的路,加油。如果你通过致力胜利进入到了心仪的公司,肯定不要懈怠放松,职场成长和新技术学习一样,逆水行舟。如果有幸咱们江湖再见!

另外,我开源的各个 PDF,后续我都会继续更新和保护,感激大家长期以来对冰河的反对!!

退出移动版