本来说要写的,咕了一个月。

正好最近搞了台新的小鸡,准备把 CI 迁过去,顺便复习一下 Woodpecker CI 的搭建过程。

这里就直接绑定自建的 gitea 了,比较贴近实际使用场景。

环境

Debian 11

主要依赖: nginx, docker, docker-compose

使用 nginx 官方 mainline 源

sudo apt install curl gnupg2 ca-certificates lsb-release debian-archive-keyring
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
    | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/mainline/debian `lsb_release -cs` nginx" \
    | sudo tee /etc/apt/sources.list.d/nginx.list

echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \
    | sudo tee /etc/apt/preferences.d/99nginx
    
sudo apt update
sudo apt install nginx

添加 docker 自有的镜像源

sudo apt-get update
# sudo apt-get install \
#     ca-certificates \
#     curl \
#     gnupg \
#     lsb-release
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin

在 Gitea 添加 OAuth2 Application

创建一个 OAuth2 应用,以便用户向其授权获取账户信息,并在 CI 运行时 clone 私有仓库。

登录 Gitea 实例。进入 Settings - Applications - Manage OAuth2 Applications (/user/settings/applications), 在 “Create a new OAuth2 Application” 中添加。

Application Name 随意,

Redirect URI 填写如 https://ci.example.com/authorize , 将 ci.example.com/ 换作自己的 URI 即可。

随后应该得到 Client ID 和 Client Secret, 其中的 ID 以 UUID 形式出现,而 Secret 需立即复制, 此后不会再显示。

启动容器

既然 官方也推荐用 docker 容器 ,那就用呗。

编写 docker-compose.yml .

其中的环境变量需要自己填写。

WOODPECKER_OPEN=true 无需更改。
WOODPECKER_ORGS 填写自己在 gitea 中的组织名称。
WOODPECKER_ADMIN 填写自己在 gitea 中的 username.

WOODPECKER_HOST 填写 CI 将要用的 Hostname, 如 https://ci.example.com . 能否在 path 下工作暂不清楚。
WOODPECKER_AGENT_SECRET 有两处,需填写相同的值,不妨用 openssl rand -hex 32 生成。

WOODPECKER_GITEA=true 无需更改。
WOODPECKER_GITEA_URL 填写 Gitea 的 URL, 例如 https://example.com/git , https://git.example.com .
WOODPECKER_GITEA_CLIENT 填写刚才得到的 Client ID.
WOODPECKER_GITEA_SECRET 填写刚才得到的 Client Secret.

WOODPECKER_SERVER_CERTWOODPECKER_SERVER_KEY 直接留空,TLS 交给 nginx 处理,不会有影响。

# docker-compose.yml
version: '3'

services:
  woodpecker-server:
    image: woodpeckerci/woodpecker-server:latest
    restart: unless-stopped
    ports:
      - 127.0.0.1:8000:8000
    volumes:
      - ./server-data:/var/lib/woodpecker/
    environment:
      # - WOODPECKER_LOG_LEVEL=trace
      - WOODPECKER_OPEN=true
      - WOODPECKER_ORGS=<YOUR_ORG_NAME>
      - WOODPECKER_ADMIN=<YOUR_ADMIN_NAME>

      - WOODPECKER_HOST=<YOUR_CI_URL>
      - WOODPECKER_AGENT_SECRET=<YOUR_AGENT_SECRET>

      - WOODPECKER_GITEA=true
      - WOODPECKER_GITEA_URL=<YOUR_GITEA_URL>
      - WOODPECKER_GITEA_CLIENT=<YOUR_GITEA_OAUTH2_APP_UUID>
      - WOODPECKER_GITEA_SECRET=<YOUR_GITEA_OAUTH2_APP_SECRET>

      - WOODPECKER_SERVER_CERT=
      - WOODPECKER_SERVER_KEY=

  woodpecker-agent:
    image: woodpeckerci/woodpecker-agent:latest
    command: agent
    restart: unless-stopped
    depends_on:
      - woodpecker-server
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    environment:
      - WOODPECKER_SERVER=woodpecker-server:9000
      - WOODPECKER_AGENT_SECRET=<YOUR_AGENT_SECRET>

配置反代

此处使用 nginx.

一定不要忘记申请证书!可以用 acme.sh 快速申请。我的踩坑经历

配置 HTTP Server.

# /etc/nginx/conf.d/ci.example.com.conf
    server {
        listen 127.0.0.1:8001 ssl http2;
        server_name  ci.example.com;

        if ($http_user_agent ~* "qihoobot|Baiduspider|Googlebot|Googlebot-Mobile|Googlebot-Image|Mediapartners-Google|Adsbot-Google|Feedfetcher-Google|Yahoo! Slurp|Yahoo! Slurp China|YoudaoBot|Sosospider|Sogou spider|Sogou web spider|MSNBot|ia_archiver|Tomato Bot|^$") {  
            return 404;
        }

        # HSTS    
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; 
        ssl_certificate /path/to/certificate;
        ssl_certificate_key /path/to/certificate_key;
        #keepalive_timeout   70;
        
        # OCSP stapling
        ssl_stapling        on;
        ssl_stapling_verify on;
        resolver 1.0.0.1;
        
        ssl_protocols TLSv1.3;
        # ssl_ciphers TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256;
        ssl_prefer_server_ciphers on; 
        
        location / {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-Port $server_port;
            proxy_pass http://127.0.0.1:8000; 
        }    
    } 

配置 stream 模块

# /etc/nginx/conf.d/stream.conf
stream {
    map $ssl_preread_server_name $name {
        ci.example.com ci;
    }
    upstream ci {
        server 127.0.0.1:8001; 
    }
    server {
        listen *:443 reuseport;
        include /etc/nginx/conf.d/whitelist.conf;
        proxy_pass	$name;
        ssl_preread on;
    }
} 

然后把这两个配置 include 到对应的地方就行了。然后重启下 nginx.

systemctl reload nginx

安全性(可选)

把域名挂到 互联网皇帝 那里,各种防火墙拉满。

同时给 nginx 加个 IP 白名单。

验证

最后访问网址,应该可以看到啄木鸟和旁边的 login 按钮。

点击后,应自动跳转至预设的 Gitea 实例,获取 OAuth2 授权后即可登录。

随后就应该能进入界面,并添加项目了。