环境: 基于Drone+Gitea+Docker对go项目进行CI/CD
目标: 把原来由docker run
起来的进程交给k8s去进行调度编排
前提: 熟悉k8s的基本使用
1.kubectl环境打包
这里把用户目录下的.kube目录和kubectl程序放到当前目录,打包成镜像,上传到私有仓库
Dockerfile
FROM alpine:3.10
COPY .kube /root/.kube
COPY kubectl /bin/
build.sh
image=192.168.41.34/pub/kubectl
ver=v1
docker build -t $image:$ver .
# 可能需要docker login
docker push $image:$ver
# 测试
docker run --rm 192.168.41.34/pub/kubectl:$ver kubectl get nodes
执行
./build.sh
2.项目代码
├── .drone.yml
├── deployment.yaml
├── deploy.sh
├── Dockerfile
├── go.mod
├── go.sum
└── main.go
main.go
package main
import (
"fmt"
"net/http"
"github.com/rs/xid"
)
var port = ":8080"
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
id := xid.New().String()
s := fmt.Sprintf("你好, id: %s", id)
fmt.Fprintf(w, "%v\n", s)
})
if err := http.ListenAndServe(port, nil); err != nil {
fmt.Println(err)
}
}
.drone.yml
kind: pipeline
name: default
clone:
depth: 10
steps:
# 开发版
- name: docker-${DRONE_BRANCH}
image: plugins/docker:18.09
settings:
username: drone
password:
from_secret: DOCKER_PASSWORD
registry: 192.168.41.34
repo: 192.168.41.34/test/demo
insecure: true
debug: true
dockerfile: Dockerfile
tags:
- canary
when:
branch:
- master
- dev
event:
- push
# 稳定版
- name: docker-release
image: plugins/docker:18.09
settings:
username: drone
password:
from_secret: DOCKER_PASSWORD
registry: 192.168.41.34
repo: 192.168.41.34/test/demo
insecure: true
dockerfile: Dockerfile
tags:
- ${DRONE_TAG}
- latest
when:
event:
- tag
# 开发版部署
- name: k8s-deploy-${DRONE_BRANCH}
image: 192.168.41.34/pub/kubectl:v1
commands:
- namespace=dev
- version=canary
- sh deploy.sh $namespace $version
when:
branch:
- master
- dev
event:
- push
# 稳定版部署
- name: k8s-deploy-release
image: 192.168.41.34/pub/kubectl:v1
commands:
- namespace=test
- version=${DRONE_TAG}
- sh deploy.sh $namespace $version
when:
event:
- tag
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo
namespace: NAMESPACE
labels:
env: NAMESPACE
app: demo
spec:
selector:
matchLabels:
env: NAMESPACE
app: demo
replicas: 1
template:
metadata:
labels:
env: NAMESPACE
app: demo
spec:
containers:
- name: demo
image: 192.168.41.34/test/demo:VERSION
imagePullPolicy: Always
ports:
- name: http
containerPort: 8080
protocol: TCP
deploy.sh
namespace=$1
version=$2
name=demo
image=192.168.41.34/test/demo
sed -ie "s/VERSION/$version/g" deployment.yaml
sed -ie "s/NAMESPACE/$namespace/g" deployment.yaml
cat deployment.yaml
# 没有则创建Deployment对象,有则更新镜像
kubectl get deployments/$name -n $namespace || kubectl apply -f deployment.yaml
kubectl set image deployments/$name $name="$image:$version" -n $namespace
Dockerfile
FROM 192.168.41.34/pub/golang:1.12 as builder
WORKDIR /build
COPY . .
RUN CGO_ENABLED=0 GOPROXY=http://192.168.40.131:4000 go build -o demo
FROM alpine:3.10 as runner
LABEL description="the image is a demo"
WORKDIR /app
COPY --from=builder /build/demo /app/
EXPOSE 8080
ENTRYPOINT ["./demo"]
3.总结
golang项目提交代码到gitea,然后触发drone做ci/cd
drone做了以下两步,每一步都是在容器里进行,容器用完即删:
- 把项目编译打包成docker上传到私有仓库
- 运行kubectl客户端,创建Deployment对象或者更新对象的image字段值