Hero Image
Gitlab-CI Introduction

Gitlab CI Concept Gitlab DevOps GitOps Workflow code push -> pipeline -> stage -> job Design plan -> code -> build -> test -> release -> deploy -> operate -> monitor -> plan Runner Executors Shell VirtualBox Docker Docker Machine Kubernetes Else… References Gitlab CI/CD Gitlab Runner .gitlab-ci.yaml Runner Register gitlab-runner register After register concurrent = 1 check_interval = 0 [session_server] session_timeout = 1800 [[runners]] name = "public-shell" url = "https://gitlab.go2cloudten.com/" token = "-mdH9OAOzG5yPsf_AVnW" executor = "shell" [[runners]] name = "public-docker" url = "https://gitlab.go2cloudten.com/" token = "AcEGPPKTS1uuQ_A_qpWy" executor = "docker" [runners.docker] dns = ["192.168.185.5", "192.168.185.6"] tls_verify = false image = "registry.go2cloudten.com/it/office_sop/node:12.13.0" privileged = true disable_entrypoint_overwrite = false oom_kill_disable = false disable_cache = false shm_size = 0 pull_policy = "if-not-present" volumes = ["/cache"] Repository .gitlab-ci.yaml stages: - domain check-icp: stage: domain image: registry.go2cloudten.com/it/office_sop/icp tags: - docker script: - domains=$(awk -F '|' '{if($6 ~ "Y" && ($7 ~ "West" || $7 ~ "Yuqu")) print $3}' domains-info.md | sed 's/ //g' | sort | uniq) - if [[ "${domains}" == "" ]]; then telegram.sh 'There is no domain in list' ; else telegram.sh 'Start checking ICP.' ; fi - for i in ${domains}; do result=$(checkicp ${i}); if [[ "${result}" == "未备案" ]];then telegram.sh "${i} 未备案"; sleep 1 ;fi;done - telegram.sh 'ICP check completed.' only: - schedules

Hero Image
Docker Introduction

Docker Concept VM vs Container VM - Base on OS Container - Base on Application (Linux Kernel: Namespace and Cgroup) Client to Server Docker daemon - containerd, docker-containerd-shim, docker-runc Docker client - cli command docker cli -> docker daemon -> containerd -> runc -> namespace & cgroup Image Snapshots Container Read-Only processes on image Hub / Registry Store images References Docker —— 從入門到實踐 docker docs Docker commands Dockerfile ARG dist="/tmp/password" ARG projectDir="/password" FROM golang:1.16-alpine3.14 AS builder RUN apk add build-base upx ARG dist ARG projectDir WORKDIR ${projectDir} COPY . . RUN go build -trimpath -o main cmd/main.go RUN upx -9 -o ${dist} main FROM scratch ARG dist ENV TZ=Asia/Taipei COPY --from=builder ${dist} /usr/local/bin/password Dockerfile1 FROM alpine CMD ["nc","-l","12345"] Dockerfile2 FROM alpine CMD ["echo","DOCKER"] docker build command docker build . -t program docker build . -f Dockerfile -t test_mysql docker build . -t hello:v1.1 --build-arg dist=/tmp/hello --build-arg projectDir=/hello docker build . docker/status echo -e "${GREEN}Before build${RESET}" docker image ls docker build . -f docker/Dockerfile1 -t test1 docker build . -f docker/Dockerfile2 -t test2 docker image . docker/status echo -e "${GREEN}After build${RESET}" docker image ls docker run AND rm . docker/status echo -e "${GREEN}Run container1${RESET}" docker run -d --name container1 test1 echo -e "${GREEN}Run container2${RESET}" docker run -d --name container2 test2 echo -e "${GREEN}List alive containers${RESET}" docker ps echo -e "${GREEN}List all containers${RESET}" docker ps -a echo -e "${GREEN}Remove alive container${RESET}" docker rm -f container1 echo -e "${GREEN}List all containers${RESET}" docker ps -a echo -e "${GREEN}Remove exit container${RESET}" docker rm container2 echo -e "${GREEN}List all containers${RESET}" docker ps -a docker pull AND rmi . docker/status echo -e "${GREEN}List all image${RESET}" docker image ls echo -e "${GREEN}Pull alpine image${RESET}" docker pull alpine echo -e "${GREEN}List all image${RESET}" docker image ls docker rmi . docker/status echo -e "${GREEN}Remove alpine image${RESET}" docker rmi alpine echo -e "${GREEN}List all image${RESET}" docker image ls prune docker system prune -f --volumes docker history . docker/status echo -e "${GREEN}History of test1${RESET}" docker history test1 echo -e "${GREEN}History of mysql:8${RESET}" docker history mysql:8 Docker remote Edit service file # /lib/systemd/system/docker.service ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375 Restart service systemctl daemon-reload systemctl restart docker Specify DOCKER_HOST . docker/status echo -e "${GREEN}List images on 192.168.185.9${RESET}" DOCKER_HOST=192.168.185.9:2375 docker images Docker-compose version: "3" services: svn: image: zeyanlin/svn environment: - LDAP_HOSTS=${LDAP_HOSTS} - LDAP_BASE_DN=${LDAP_BASE_DN} - LDAP_BIND_DN=${LDAP_BIND_DN} - LDAP_ADMIN_PASS=${LDAP_ADMIN_PASS} ports: - 8000:80 - 3690:3690 depends_on: - ldap ldap: image: zeyanlin/openldap environment: - LDAP_DOMAIN=${LDAP_DOMAIN} - LDAP_ADMIN_PASS=${LDAP_ADMIN_PASS} ports: - 389:389 - 636:636 php: image: zeyanlin/phpldapadmin environment: - LDAP_HOSTS=${LDAP_HOSTS} ports: - 80:80 depends_on: - ldap Env LDAP_HOSTS=ldap LDAP_DOMAIN="knowhow.fun" LDAP_BASE_DN="dc=knowhow,dc=fun" LDAP_BIND_DN="cn=admin" LDAP_ADMIN_PASS="123qwe"

Hero Image
Golang基准测试

Golang 基准测试 基本使用 基准测试常用于代码性能测试,函数需要导入 testing 包,并定义以 Benchmark 开头的函数, 参数为 testing.B 指针类型,在测试函数中循环调用函数多次 ➜ go test -bench=. -run=none goos: darwin goarch: amd64 pkg: pkg06 cpu: Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz BenchmarkFib-12 250 4682682 ns/op PASS ok pkg06 1.875s ➜ go test -bench=. -benchmem -run=none goos: darwin goarch: amd64 pkg: pkg06 cpu: Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz BenchmarkFib-12 249 4686452 ns/op 0 B/op 0 allocs/op PASS ok pkg06 1.854s bench 的工作原理 基准测试函数会被一直调用直到 b.N 无效,它是基准测试循环的次数 b.N 从 1 开始,如果基准测试函数在 1 秒内就完成 (默认值),则 b.N 增加,并再次运行基准测试函数 b.N 的值会按照序列 1,2,5,10,20,50,... 增加,同时再次运行基准测测试函数 上述结果解读代表 1 秒内运行了 250 次,每次 4682682 ns -12 后缀和用于运行次测试的 GOMAXPROCS 值有关。与 GOMAXPROCS 一样,此数字默认为启动时 Go 进程可见的 CPU 数。可以使用 -cpu 标识更改此值,可以传入多个值以列表形式来运行基准测试 传入 cpu num 进行测试 ➜ go test -bench=. -cpu=1,2,4 -benchmem -run=none goos: darwin goarch: amd64 pkg: pkg06 cpu: Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz BenchmarkFib 244 4694667 ns/op 0 B/op 0 allocs/op BenchmarkFib-2 255 4721201 ns/op 0 B/op 0 allocs/op BenchmarkFib-4 256 4756392 ns/op 0 B/op 0 allocs/op PASS ok pkg06 5.826s count 多次运行基准测试 因为热缩放、内存局部性、后台处理、gc 活动等等会导致单次的误差,所以一般会进行多次测试

Hero Image
Gin中文文档

自定义路由日志的格式 Gin 运行多个服务 XML、JSON、YAML 和 ProtoBuf 渲染(输出格式) 自定义路由日志的格式 default [GIN-debug] POST /foo --> main.main.func1 (3 handlers) [GIN-debug] GET /bar --> main.main.func2 (3 handlers) [GIN-debug] GET /status --> main.main.func3 (3 handlers) import ( "log" "net/http" "github.com/gin-gonic/gin" ) func main() { r := gin.Default() gin.DebugPrintRouteFunc = func(httpMethod, absolutePath, handlerName string, nuHandlers int) { log.Printf("endpoint %v %v %v %v\n", httpMethod, absolutePath, handlerName, nuHandlers) } r.POST("/foo", func(c *gin.Context) { c.JSON(http.StatusOK, "foo") }) r.GET("/bar", func(c *gin.Context) { c.JSON(http.StatusOK, "bar") }) r.GET("/status", func(c *gin.Context) { c.JSON(http.StatusOK, "ok") }) // Listen and Server in http://0.0.0.0:8080 r.Run() } Gin 运行多个服务 package main import ( "log" "net/http" "time" "github.com/gin-gonic/gin" "golang.org/x/sync/errgroup" ) var ( g errgroup.Group ) func router01() http.Handler { e := gin.New() e.Use(gin.Recovery()) e.GET("/", func(c *gin.Context) { c.JSON( http.StatusOK, gin.H{ "code": http.StatusOK, "error": "Welcome server 01", }, ) }) return e } func router02() http.Handler { e := gin.New() e.Use(gin.Recovery()) e.GET("/", func(c *gin.Context) { c.JSON( http.StatusOK, gin.H{ "code": http.StatusOK, "error": "Welcome server 02", }, ) }) return e } func main() { server01 := &http.Server{ Addr: ":8080", Handler: router01(), ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } server02 := &http.Server{ Addr: ":8081", Handler: router02(), ReadTimeout: 5 * time.Second, WriteTimeout: 10 * time.Second, } g.Go(func() error { return server01.ListenAndServe() }) g.Go(func() error { return server02.ListenAndServe() }) if err := g.Wait(); err != nil { log.Fatal(err) } } XML、JSON、YAML 和 ProtoBuf 渲染(输出格式) SecureJSON 使用 SecureJSON 可以防止 json 劫持,如果返回的数据是数组,则会默认在返回值前加上"while(1)"