[TOC]
目前的方案主要是围绕Gitlab及其自带的gitlab-runner在搭建,如图。
如果要查看基于Gerrit和Jenkins的部署方式,请切换到v0.1分支(其中各组件版本可能有点旧了,请自行使用镜像最新版本的镜像)。
以下工具基于 Docker & Docker Compose 来部署,其中的配置全部基于“example.com”,具体部署前可根据实际情况进行批量替换。
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
并根据需要配置国内源。
参考文档.
sudo curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
容器要想访问外部网络,需要本地系统的转发支持。编辑/etc/sysctl.conf
,添加或修改:
net.ipv4.ip_forward=1
然后重启网络和docker。
systemctl restart network
systemctl restart docker
这一版,容器数据的持久化数据的挂载有限使用命名卷,而不是直接将主机目录挂载到容器里。以便避免权限等问题导致的坑。
如果开启SELinux,并且采用目录挂载挂载的方式,需要配置SELinux权限。如挂载主机目录为/srv/mysql
,则执行:
chcon -Rt svirt_sandbox_file_t /srv/mysql
iptables增加端口
配置iptable规则:vi /etc/sysconfig/iptables
# 增加一行(如增加UDP 123端口)
-A INPUT -m state --state NEW -m udp -p udp --dport 123 -j ACCEPT
firewalld开通端口
firewall-cmd --zone=public --add-port=80/tcp --permanent
systemctl restart firewalld
研发内用的DNS有dnsmasq来提供,由nginx进行反向代理。DNS的docker-compose.yml如下:
services:
dns:
image: andyshinn/dnsmasq
container_name: dns
hostname: dns
networks:
- devops
privileged: true
cap_add:
- NET_ADMIN
ports:
- "53:53"
- "53:53/udp"
volumes:
- './etc_dnsmasq.conf:/etc/dnsmasq.conf'
- './etc_resolv.dnsmasq:/etc/resolv.dnsmasq'
- './etc_dnsmasq.hosts:/etc/dnsmasq.hosts'
容器的三个配置文件通过volume的方式与主机当前目录下的配置文件共享。
DNS服务使用的是dnsmasq。其中,
/etc/dnsmasq.conf
是主配置文件,主要内容有两行:
# 指定配置外网DNS地址的resolv文件
resolv-file=/etc/resolv.dnsmasq
# 指定配置内网域名解析关系的文件
addn-hosts=/etc/dnsmasq.hosts
/etc/resolv.dnsmasq
,配置外网DNS地址,内容如下:
nameserver 114.114.114.114
nameserver 202.106.0.20
/etc/dnsmasq.hosts
,配置内网域名解析,内容如下:
# ops
172.31.0.254 dns ntp dns.example.com ntp.example.com
172.31.0.253 nas nas.example.com
172.31.3.101 vcenter vcenter.example.com
172.23.0.100 ldap ldap.example.com
172.23.0.101 jira jira.example.com
... ...
平台由多个组件构成,涉及多个不同的IP和端口号,为了方便记忆,采用域名+反向代理的配置方式。反向代理用Nginx提供,docker-compose.yml
如下:
services:
nginx:
image: nginx
container_name: nginx
hostname: nginx
networks:
- devops
# dns:
# - 172.31.0.254
privileged: true
ports:
- "80:80"
- "443:443"
volumes:
- ./conf.d:/etc/nginx/conf.d # 1
- ./www:/var/www # 2
- ./ssl:/etc/nginx/ssl # 3
- 所有的反向代理配置放在
conf.d
目录下,随着下面各个组件的介绍会继续补充; - 静态页面放在
www
目录下; - 证书放在
ssl
下。
LDAP使用OpenLDAP进行维护,使用phpldapadmin管理界面。这一版的LDAP增加了SSL支持,因此需要提供证书。docker-compose.yml如下:
services:
ldap:
image: osixia/openldap
container_name: ldap
hostname: ldap
networks:
- devops
ports:
- "389:389"
- "636:636"
environment:
- LDAP_ORGANISATION=ExampleCom
- LDAP_DOMAIN=example.com
- LDAP_ADMIN_PASSWORD=passwd
- LDAP_READONLY_USER=true
- LDAP_READONLY_USER_USERNAME=readonly
- LDAP_READONLY_USER_PASSWORD=passwd
- LDAP_TLS_CRT_FILENAME=ldap.example.com.crt #1
- LDAP_TLS_KEY_FILENAME=ldap.example.com.key #1
- LDAP_TLS_CA_CRT_FILENAME=root.example.com.crt #1
volumes:
- ./ssl:/container/service/slapd/assets/certs #1
- ldap-var:/var/lib/ldap
- ldap-etc:/etc/ldap/slapd.d
logging:
driver: "json-file"
options:
max-size: "200k"
max-file: "10"
ldap-admin:
image: osixia/phpldapadmin
container_name: ldap-admin
hostname: ldap-admin
depends_on:
- ldap
networks:
- devops
# If nginx not on the same "devops" network, uncomment the following two lines.
# ports:
# - "8080:80"
# - "8443:443"
environment:
- PHPLDAPADMIN_LDAP_HOSTS=ldap
- PHPLDAPADMIN_HTTPS_CRT_FILENAME=ldap.example.com.crt #1
- PHPLDAPADMIN_HTTPS_KEY_FILENAME=ldap.example.com.key #1
- PHPLDAPADMIN_HTTPS_CA_CRT_FILENAME=root.example.com.crt #1
volumes:
- ./ssl:/container/service/phpldapadmin/assets/apache2/certs #1
- ldap-admin:/var/www/phpldapadmin
logging:
driver: "json-file"
options:
max-size: "200k"
max-file: "10"
- 证书文件通过卷挂载,并使用环境变量进行指定。
以Jira为例,docker-compose.yml如下:
version: '3'
services:
mysql-jira:
image: mysql:5.7
container_name: mysql-jira
environment:
- MYSQL_ROOT_PASSWORD=devops
- MYSQL_DATABASE=jiradb #1
- MYSQL_USER=jira #1
- MYSQL_PASSWORD=devops #1
networks:
- devops
volumes:
- ./mysql/mysqld_jira.cnf:/etc/mysql/conf.d/mysqld_jira.cnf #3
- mysql-jira:/var/lib/mysql
logging:
driver: "json-file"
options:
max-size: "200k"
max-file: "10"
jira:
image: atlassian/jira-software
container_name: jira
hostname: jira
depends_on:
- mysql-jira
ports:
- "8081:8080"
environment:
- JVM_MINIMUM_MEMORY=512m
- JVM_MAXIMUM_MEMORY=2048m
- ATL_PROXY_NAME=jira.example.com #2
- ATL_PROXY_PORT=443 #2
- ATL_TOMCAT_SCHEME=https #2
- ATL_TOMCAT_SECURE=true #2
networks:
- devops
volumes:
- ./mysql/mysql-connector-java-5.1.48.jar:/opt/atlassian/jira/lib/mysql-connector-java-5.1.48.jar #3
- jira:/var/atlassian/application-data/jira
- 启动MySQL的时候即初始化好数据库和用户;
- Jira前方经过反向代理,而反向代理配置了SSL;
- Jira对数据库有编码的要求,
./mysql/mysqld_jira.cnf
中可见:
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_bin
Jira和Confluence的破解方法,仅用于学习,企业用户请购买正版。
注意,由于gitlab的SSH默认使用的是22端口,因此主机的sshd建议修改为其他端口。编辑/etc/ssh/sshd_config
增加2222端口:
#Port 22
Port 2222
然后执行如下命令为SELinux开启2222端口:
semanage port -a -t ssh_port_t -p tcp 2222
然后执行如下命令让防火墙通过2222端口:
firewall-cmd --permanent --add-port=2222/tcp
systemctl restart firewalld.service
使用gitlab官方docker镜像,docker-compose.yml文件如下:
services:
gitlab:
image: gitlab/gitlab-ce
container_name: gitlab
hostname: gitlab
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'https://gitlab.example.com' #1
nginx['redirect_http_to_https'] = true #1
ports:
- "2222:22"
- "8080:80"
- "8443:443"
networks:
- devops
volumes:
- gitlab-config:/etc/gitlab #2
- gitlab-logs:/var/log/gitlab #2
- gitlab-data:/var/opt/gitlab #2
logging:
driver: "json-file"
options:
max-size: "200k"
max-file: "10"
- 由于gitlab前方有支持SSL的反向代理,external_url为用户使用的地址;此处
GITLAB_OMNIBUS_CONFIG
环境变量可用于提前给出任意gitlab.rb
中的配置。
挂载目录如下:
主机目录 | 容器目录 | 内容 |
---|---|---|
gitlab-data | /var/opt/gitlab | 应用数据 |
gitlab-logs | /var/log/gitlab | 日志 |
gitlab-config | /etc/gitlab | GitLab配置文件 |
由于配置文件已经共享到宿主机,因此可以通过编辑gitlab-config
卷中的gitlab.rb
配置gitlab:
###! **remember to close this block with 'EOS' below**
gitlab_rails['ldap_servers'] = YAML.load <<-'EOS'
main: # 'main' is the GitLab 'provider ID' of this LDAP server
label: 'LDAP'
host: 'ldap.example.com'
port: 389
uid: 'cn'
bind_dn: 'cn=admin,dc=example,dc=com'
password: '<passwd of admin>'
encryption: 'plain' # "start_tls" or "simple_tls" or "plain"
verify_certificates: true
active_directory: false
allow_username_or_email_login: true
lowercase_usernames: true
block_auto_created_users: false
base: 'dc=example,dc=com'
user_filter: ''
## EE only
group_base: ''
admin_group: ''
sync_ssh_keys: false
EOS
然后执行如下命令使gitlab配置生效:
docker exec -it gitlab gitlab-ctl reconfigure
Sonarqube没有太多可解释的,与Jira或Confluence类似,就是典型的一个数据库+一个应用的部署方式,数据库启动时自动创建database和相应的用户的密码;SonarQube为官方镜像。
SonarQube中用到的插件可以到SonarQube插件库下载,并复制到sonar-extensions
卷的plugins
目录下,并重启使其生效。
仍然采用容器的部署方式,采用官方镜像sonatype/nexus3
。
使用nginx
进行反向代理,将不同的域名映射到不同的nexus端口或路径。
因此docker-compose.yml
文件内容如下:
services:
nexus:
image: sonatype/nexus3
container_name: nexus
hostname: nexus
networks:
- devops
ports:
- "8081:8081"
volumes:
- nexus-data:/nexus-data
registry:
image: registry:2
container_name: registry
networks:
- devops
ports:
- 5000:5000
environment:
- REGISTRY_PROXY_REMOTEURL="https://docker.mirrors.ustc.edu.cn"
volumes:
- registry:/var/lib/registry
由于研发人员经常需要上Google,或查询各种技术官网资料,因此一个统一的上网代理还是有必要的。
这里使用SOCKS5来做外网的代理,支持PAC模式和全局代理模式。
- 代理使用sslocal,代理服务器的配置通过json文件传给该命令,端口为1080;
- sslocal的代理为socks协议,因此使用privoxy转为http协议,端口为8118,该代理地址可用于全局代理模式的配置;
- PAC代理模式维护一个list,只有list中的网址是走代理的,通过一个pac文件来维护,同时指定了SOCKS代理的地址,将该pac文件用http服务提供出来,使用者直接配置该pac文件的http地址即可使用PAC方式上网。
以上,第1,2由sgrio/alpine-sslocalproxy
容器提供;第3条就起一个httpd
容器,将pac文件用http访问即可。docker-compose.yml如下:
services:
proxy:
image: sgrio/alpine-sslocalproxy
container_name: proxy
hostname: proxy
networks:
- devops
privileged: true
ports:
- "1080:1080"
- "8118:8118"
volumes:
- './ss-client.json:/etc/shadowsocks-libev/config.json' # 1
- 代理服务器的配置通过volume挂载
ss-client.json
文件实现。
pac的内容放在nginx/www/pac
中通过挂载到nginx的目录下,从而可以直接通过地址proxy.example.com/pac
访问。
pac的生成通过gen-pac.sh
命令生成,该命令会从gfwlist
拉取一份常用的代理网站地址list,另外还会加上whitelist
中自定义的list,生成pac文件index.html
。
代码中的代理配置信息(
infra/ss-client.json
)无效。