阅读 396

web项目迁移到k8s

这篇文章应该会很长。

前言

小说 是我以前写的一个项目,主要是为了练手vue,后端用lumen(php框架)写的。附上码云的链接 vue-novel,前后端代码都很简单。最近把它迁移到了k8s,配合gitlab-runner和rancher-ui实现了CI/CD,在此记录一下。附上迁移后的项目地址:

最开始这个项目是怎么运行的呢?我在vultr买了个vps,安装 lnmp 集成环境,项目代码用FTP传上去,配置一下nginx就跑起来了。迁移到k8s后,提交和发布代码的大致流程如下:

  1. 把代码推送到master分支
  2. gitlab-runner自动打包镜像并推送到docker私有仓库
  3. 进入rancher后台界面,把项目的镜像更新为刚才的镜像

可以看到,我们要做的仅仅是推送代码,然后去后台更新项目的镜像,项目就上线了。

需要准备的

  1. 至少两台vps,并且相互之间可以ping通。
  2. gitlab仓库(自己搭建或直接用官网都行)。
  3. 自己的域名。

需要做的

  • 打包两个docker的基础镜像。所有后端代码用一个基础镜像,前端代码用另一个。
  • 搭一个k8s集群。我选择用 k3s。这是个精简版的k8s,功能够用,搭建简单,对机器配置要求低。
  • 搭一个rancher-ui。rancher2.0,搭建也很简单,用来可视化地操作k8s集群。
  • 搭一个docker私有仓库。有 官方镜像,可以参考一下,我是搭好集群后直接用rancher搭了个docker私有仓库。
  • 搭一个gitlab或者用 官网,把项目放进去。我是直接用的官网。
  • 配置gitlab-runner
  • 改一下项目的目录结构,给项目编写 .gitlab-ci.yml、Dockerfile、nginx.conf 3个文件
  • 最最重要的一点,把机器(也就是vps)配置好,不然会出现各种问题。

vps配置

每台vps都要配置。

#!/bin/sh

# 1. stop firewalld
systemctl stop firewalld && systemctl disable firewalld

# 2. stop SElinux
sudo sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config

# 3. set timezone
timedatectl set-timezone Asia/Shanghai

# 4
yum install vim htop -y

# 5. increase swap
dd if=/dev/zero of=/home/swap bs=1024 count=5120000
/sbin/mkswap /home/swap
/sbin/swapon /home/swap

# 6. install docker
curl -fsSL get.docker.com | sh
systemctl start docker && systemctl enable docker

复制代码

增加交换内存是因为我机器配置不够,才1G内存;防火墙和SElinux是一定要关闭的,不然集群肯定搭建不成功;docker也要安装一下。

基础镜像打包

代码上容器肯定要用镜像,说一下需要什么镜像。

后端用php,那么需要一个nginx-php镜像,我在github上找了一个,不过有一点小bug,fork过来稍微改了下,附上链接:nginx-php。 这个镜像基于alpine,然后源码安装了php和nginx,我们自己扩展和更新比较方便。根据这个Dockerfile打包镜像,然后推送到 dockerhub,最终得到一个 nginx-php镜像。如果不想让你的基础镜像公开,可以不推到dockerhub,等私有仓库搭好后放到私有仓库。至于怎么打包和推送镜像,这个比较简单,就不细说了。

前端的同理,把Dockerfile里安装php相关的部分删掉,打包并推送镜像,最终得到一个 nginx 镜像。

搭建k8s集群

server搭建

使用k3s搭建集群其实就是几个命令的事,但是国内服务器不行,因为k8s依赖pause镜像,这个镜像你在国内肯定下不下来,所以国内搭集群只能手动。

自动搭建

运行官方脚本。

curl -sfL https://get.k3s.io | sh -
复制代码

看到systemd: Starting k3s就可以了。修改配置:

vim /etc/systemd/system/multi-user.target.wants/k3s.service
复制代码

把ExecStar的值改为

/usr/local/bin/k3s server --docker --no-deploy traefik --cluster-secret=hjp
复制代码
  • --docker 用docker做底层容器(默认的是containerd)
  • --no-deploy traefik 不安装traefik组件
  • --cluster-secret=hjp 设置密码,待会添加agent(节点)就不需要去查看token了

然后重新加载配置,重启k3s。

systemctl daemon-reload
systemctl restart k3s
复制代码

运行

k3s kubectl get nodes
复制代码

查看一下节点

有一个master节点,这是安装server的时候自带的,这样其实就已经创建了有一个master节点的k8s集群。

注意这里有个坑。 按照官方文档的说法,其实可以直接运行命令的时候指定配置

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--docker --no-deploy traefik --cluster-secret=hjp" sh -
复制代码

这样就不用再修改配置。但是这样启动k3s后,后面搭建docker私有仓库、docker-registry配置ingress会一直显示initializing,所以还是安装后手动修改配置吧。

手动搭建

我是国外的服务器,所以直接用脚本搭建的,k3s的 官方文档 最下面写了怎么手动搭建。其实就是去github上把 k3s 下载,然后上传到服务器运行。然而国内服务器要多做一步,即在这之前先把pause镜像手动下载,重新打个tag。dockerhub上有个镜像谷歌仓库,附上链接 pause镜像

docker pull mirrorgooglecontainers/pause:3.1
docker tag mirrorgooglecontainers/pause:3.1 k8s.gcr.io/pause:3.1
复制代码

把下载的k3s文件复制到/usr/local/bin/k3s

cp ./k3s /usr/local/bin/k3s
chmod 777 /usr/local/bin/k3s
复制代码

启动k3s

k3s server &
复制代码

之后的操作步骤应该跟自动搭建是一样的。

k3s命令目录

k3s命令目录在/usr/local/bin/

要卸载的话,先运行k3s-killall.sh,再运行k3s-uninstall.sh。

搭建rancher-ui

ui搭建

接下来要搭个 rancher 界面来操作集群,其实也是一个命令的事。进入另一台vps,执行

docker run -d -v /var/lib/rancher/:/var/lib/rancher/ --restart=unless-stopped --name rancher-server -p 80:80 -p 443:443 rancher/rancher:stable
复制代码

注意rancher和k3s不能装在同一台机器上,不然这个容器启动会报错。k3s V0.8.1版本的时候还是可以的,不知道最近更新了什么,附上 github该问题的链接。把域名(rancher.hjply.com)指向这台vps的ip,然后浏览器访问rancher.hjply.com。由于rancher是自签名证书,会弹出安全警告,直接无视即可。

设置密码后进入。

搭建完成,右下角可以切换语言。

集群导入

把集群导入rancher后,才能可视化地操作集群。

在刚才的页面点击 "添加集群",选择 “导入现有的Kubernetes集群”, 名字随便写个,点创建

进入这个页面

复制最后一条命令,在k3s server那台机器上执行

过一会自动跳转到这个页面

状态会从waiting变成active,表示导入完成。

如果这个状态一直没变化,或者页面没有自动跳转,估计就是防火墙、SElinux没关,或者k3s和rancher两台机器互相ping不通。

导入成功后查看一下集群。

可以看到有一个节点,就是k3s server自带的master节点,如果有需要可以继续添加节点。

集群添加节点

再开一台机器,vps配置同上,然后配置一个host

vi /etc/hosts
复制代码

加一条

127.0.0.1 vultr3
复制代码

运行命令

curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--docker --node-name=vultr3" K3S_URL=https://217.69.8.236:6443 K3S_CLUSTER_SECRET=hjp sh -
复制代码
  • --node-name一定要设置,还要把节点名称(随便填写,如:vultr3)指向本机ip,并且node-name不能和已有的节点名称重复。如果不设置node-name就会默认使用机器的hostname,可能会重复导致加入集群失败。
  • K3S_URL就是k3s server就填k3s server这台机器的ip
  • K3S_CLUSTER_SECRET就是创建k3s server时候设置的密码

再查看一下集群。

看到有2个节点,表示成功。

Docker私有仓库搭建

直接用rancher搭建私有仓库比较方便。

先进入集群页面,创建一个项目。点击添加项目,项目名称随便写,系统的这2个项目(Default和System)不要动。

进入这个项目,然后进到应用商店。

点“启动”,选择docker-registry,点“查看详情”进入部署页面。

部署的时候需要注意2点。

  1. 需要一个ssl证书
  2. 需要手动生成帐号密码

为什么需要启用https?因为我们要使用帐号密码控制私有仓库的访问权限,不能谁都可以往里面push镜像,而启用帐号密码就必须用https(官方文档要求,如图)。

直接在阿里云申请个免费证书,下载到电脑

在这里插入图片描述

接下来就是生成帐号密码。进入k3s server那台机器(一定要用这台机器,因为不同机器生成的密码不一样),依次执行:

mkdir -p /home/registry/auth

docker run --entrypoint htpasswd registry -Bbn hjp hjp >>/home/registry/auth/htpasswd

cat /home/registry/auth/htpasswd
复制代码

(帐号hjp,密码hjp)_

复制一下生成的密码,填入部署页面

配置一下负载均衡,使用自定义域名(registry.hjply.com指向k3s server这台机器)

点击启动,就创建了docker仓库。这里我没有做持久化配置,所以容器删掉后里面的镜像也会被删除。最后还差一步配置ssl和帐号密码。

进入证书页面

添加证书,把从阿里云下载的证书导入,点击保存即可。

然后升级一下仓库的ingress,点击“升级”,把SSL证书勾选上,保存。

这样仓库的https就配置好了,我们测试一下,打开网页 registry.hjply.com/v2/_catalog

输入账号密码

看到仓库是空的,里面没有镜像,到此docker私有仓库就搭建完了。最后还要把仓库的账号密码保存在集群,因为待会拉取镜像需要权限认证。

点击镜像库凭证

把帐号密码填写一下,保存即可。

gitlab-runner配置

gitlab-runner有3种,即

  • Specific Runners
  • Shared Runners
  • Group Runners

其中Specific Runners是针对项目的,每个项目可以分别配置自己的runner;

Shared Runners是gitlab上别人共享出来的runner,我们不用,把它禁用掉;

Group Runners是针对项目组的,只要给项目组配置一个runner,组内的所有项目都可以使用这个runner。

新建一个group,把项目都放进去

进入group_hjp的CI/CD配置页面

可以看到现在还没有安装runner。找一下 文档,里面有写怎么安装gitlab-runner,我们直接在vps上安装,依次运行

curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh | sudo bash

sudo yum install gitlab-runner
复制代码

即可。安装之后需要注册,运行

gitlab-runner register
复制代码

  • URL填gitlab的地址,如果没有自己搭建的话,就是https://gitlab.com/
  • token去刚才CI/CD的页面复制一下
  • description随便写
  • tags随便写,多个用逗号分隔
  • executor看你的gitlab-runner用来做什么,我是用来执行shell,所以选shell

这样就注册完成了。刷新网页验证一下

进入到项目的CI/CD页面,验证Groups Runners是否可用。

最后,因为待会要用这个runner打包和推送镜像到docker私有仓库,所以还需要配置一下docker。

先把私有仓库地址加入docker配置文件(新版docker没有这个文件,直接vim创建即可)

vim /etc/docker/daemon.json
复制代码

把私有仓库地址写入文件,保存退出。

重新加载docker配置

systemctl reload docker
复制代码

同理,在k3s server上也要把私有仓库地址加到/etc/docker/daemon.json配置文件里,因为拉取镜像需要用。

然后切换到gitlab-runner用户,登录registry.hjply.com并保存账号密码

如果报 /var/run/docker.sock 没有权限的错误,需要把gitlab-runner这个用户添加到docker用户组

usermod -G docker gitlab-runner
复制代码

到这里gitlab-runner和docker配置就完成了。

项目改造

以后端代码为例,先把目录层级改一下。

我们加个src目录,把代码全放进去,然后开始编写 .gitlab-ci.yml、Dockerfile、nginx.conf文件

nginx.conf

server {
    listen 80 default_server;

    client_max_body_size 5m;
    client_body_buffer_size 256k;
    client_header_buffer_size 256k;
    large_client_header_buffers 4 8k;

    set     $rootPath       '/data/src/public';
    root    $rootPath;

    index index.php index.html index.htm;

    server_name localhost;

    if (!-e $request_filename) {
        rewrite ^/(.*)$ /index.php/$1 last;
    }

   location ~ ^(.+\.php)(.*)$ {
        fastcgi_pass            unix:/usr/local/php/var/run/php-fpm.sock;
        fastcgi_index           index.php;
        fastcgi_split_path_info ^(.+\.php)(.*)$;
        fastcgi_param           PATH_INFO $fastcgi_path_info;
        fastcgi_param           SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        fastcgi_buffer_size     128k;
        fastcgi_buffers         256 16k;
        client_body_buffer_size 1024k;
        include                 fastcgi_params;
    }

}
复制代码

这就是个很普通的php项目nginx配置,就不多说了。

Dockerfile

FROM hongjiapei/nginx-php

COPY nginx.conf /usr/local/nginx/conf.d/nginx.conf

COPY src /data/src

RUN chown -R www-data.www-data /data/src/ && chmod -R 755 /data/src \
    && rm -rf /usr/local/php/etc/php-fpm.d/www.conf

WORKDIR /data/src

EXPOSE 80

CMD sh -c 'nginx && php-fpm -D && tail -f /usr/local/nginx/logs/error.log'

复制代码

继承了我们之前打包的nginx-php镜像,然后用自己的nginx.conf覆盖掉默认的配置,最后前台启动nginx和php-fpm、打印nginx错误日志。注意这里不能后台启动nginx和php-fpm,不然等你命令执行完了容器就自动退出了。

.gitlab-ci.yml

stages:
  - build
  - push

build_image:
  stage: build
  script:
    - ls -la
    - CI_COMMIT_TAG=`git log | grep -e "^commit.*" | wc -l` && docker build --pull -t registry.hjply.com/group_hjp/xsbe:"$CI_COMMIT_TAG" .
  only:
    - master
  tags:
    - abc

push_image:
  stage: push
  script:
    - CI_COMMIT_TAG=`git log | grep -e "^commit.*" | wc -l` && docker push registry.hjply.com/group_hjp/xsbe:"$CI_COMMIT_TAG" && docker rmi registry.hjply.com/group_hjp/xsbe:"$CI_COMMIT_TAG"
  only:
    - master
  tags:
    - abc

复制代码

这里分为两步,第一步打包镜像,第二步推送镜像。only:master表示只有master推送的时候才启动流水线,tags:abc表示使用tag包含abc的runner,所以刚才注册gitlab-runner写的tag是什么这里就写什么,git log | grep -e "^commit.*" | wc -l 表示git日志里带有commit关键字的条数,一般提交一次就多一条,我们用这个数字作为镜像的tag,推送完镜像后把本机的镜像删掉。

到这里配置就全部完成了,接下来提交代码测试一下。

提交和发布代码

提交代码

在master提交代码,进入项目页面查看

可以看到项目正在执行流水线,点进去看下

等两个阶段都成功就表示执行完成,查看一下镜像

刚才提交的代码镜像是registry.hjply.com/group_hjp/xsbe:4

发布代码

初次部署

进入rancher后台,第一次需要部署服务,以后只需要更新。

点击“部署服务”,使用刚才的镜像启动,把80端口暴露出来,部署服务之前要确保两件事

  1. k3s server这台机器 /etc/docker/daemon.json已经配置了insecure-registry
  2. 已经在集群保存了镜像库凭证

如果没配置好,镜像拉取会失败的。

等状态变成active就表示部署完成

然后配置ingress,这样就可以通过域名把请求转发到容器。

进入“负载均衡”,点击“添加ingress规则”

把域名指向容器的80端口,保存。

初次部署基本完成,打开网页验证一下(要提前把这个域名指向k3s server这台机器)。

项目配置

刚才只用了一个pod启动项目,如果性能不够,可以多加几个pod,点击那个“+”号即可。

到这里项目还没有完全部署完成,还差最后一步,即配置文件。lumen的配置文件为.env文件,一般数据库、redis配置都写在里面,这个文件肯定不会放在git里,下面说一下怎么给项目添加配置文件。

点击“配置映射”

键就用配置文件的文件名.env,值就是文件内容,可以填多行,保存,然后升级项目。

给项目添加一个ConfiMap卷,保存。

等项目自动更新pod。

更新完成,随便进入一个pod,查看一下是否有.env文件。

有.env文件,打开看一下是否正确

跟刚才配置的一样,到这里初次部署就完成了。

项目更新

项目更新就比较简单了,新增一个接口xsbe.hjply.com/test,在master提交代码,等流水线执行完,然后去看看镜像的tag是什么

去rancher后台更新一下项目

把tag改为刚才镜像的tag,保存即可。

等pod更新完后,打开网页验证一下

说明代码更新成功。

流水线失败的处理

流水线失败不可怕,根据报错信息去解决即可。以前端项目为例,提交代码后发现流水线失败了

点进去看看报错信息

发现是npm命令找不到,原来是gitlab-runner这台机器忘了装nodejs,安装一下

yum install nodejs -y
复制代码

点击最右边的刷新按钮重新执行流水线

成功后去看看镜像的tag

去rancher后台部署一下

配置ingress

部署完成,打开网页测试一下

到这里就完成了。

最后我们看一下私有仓库里的镜像

就是我们刚才推送的2个镜像。

最后

  • 数据库并没有打算用k8s来部署,因为数据库是有状态应用,要考虑数据的存储、可用性、扩展性、事务、灾备等等,太复杂了。
  • docker-registry应该把数据存在机器上,不然重启就没了,当然最好还是不要用k8s来部署。
  • 每次master提交都会生成一个镜像,这样发布和回滚代码都比较方便。
  • 机器不够了可以随时添加,项目挂了会自动重启,重试若干次还是没有成功才会启动失败。
  • rancher还有很多功能,可以看 官方文档
关注下面的标签,发现更多相似文章
评论