Building EDA server from scratch

前言

老和山职业技术学院读书的时候就开始从事实验室的兼职网管,负责实验室的网络建设以及服务器的维护,也是时候写个文章把攒了这么多年的知识科普一下。

硬件

  • portal: 登录服务器,也是终端用户唯一可以访问的机器
  • core: 核心服务器,上面部署了ipa,jenkins,gitlab,jira,sungrid等服务
  • grid00: 运算服务器1,用作sungrid的computing node
  • grid01: 运算服务器2,用作sungrid的computing node
  • netapp: 存储服务器,做芯片的一般就用netapp

网络配置

参考的网络拓扑如下

  • 一个内网段 10.0.2.0/24 (用于服务器之间的通信)
  • 一个外网IP 192.168.5.100 用于终端客户的访问
  • 自定义域名: ic.X.com

系统安装

系统推荐用centos 7.9, 当然也可以用最新的centos 8 stream。在某些最新的server上面,硬件已经不支持centos 7了,所以只能装centos 8. 8和7的系统稍微在配置上稍微有一些差别。 安装的时候把一些开发者工具都给装上可以避免后续很多问题。

portal

对外的网卡 ext: ip 配置成 192.168.5.100
对内的网卡 int: ip 配置成 10.0.2.1
配置网卡的时候一些注意事项

  • NetworkManager的影响: 如果是直接修改 /etc/sysconfig/network-scripts的方式进行配置的话,记得里面加一行 NM_CONTROLLED=no ,或者干脆就把NetworkManger卸载掉得了
  • 网卡的名字: 默认的名字总是奇奇怪怪,早起的叫ethX,后来变成emX,如果是光口,名字可能叫做p1p2这种,这种名字可以在ifcfg-xx 里面进行修改 可以使用以下命令对网卡名字做动态修改
1
ip link set old_device_name name new_device_name

如果是要静态修改的话需要对ifcfg-xx做以下修改

  • 将ifcfg_old_name重命名为ifcfg_new_name
  • 将文件里面的DEVICE和NAME修改为new_name
  • HWADDR需要修改成网卡的真实地址

core

网卡 int: ip 配置成10.0.2.100 额外注意事项

  • 该机器最后会当做flexlm的license server,有些license daemon是挑网卡名字的,比如TSMC的一定要求网卡的名字是eth 打头,所以请至少保留一块网卡地址用这个名字
  • 如果有改MAC地址需求的,需要再ifcfg-xx 里面需要用HWADDR指定网卡之前的MAC地址,让后用MACADDR指明需要更改的MAC地址

grid00

网卡 int: ip 配置成 10.0.2.10

grid01

网卡 int: ip 配置成 10.0.2.12

netapp

取决于买的型号类型,一般需要配置业务口和管理口,后者仅用于管理功能,带宽需求不大。业务口的话推荐做链路聚合。

软件安装及配置

ssh 免密登录

首先产生密钥对

1
ssh-keygen -t ed25519

不用RSA的原因是RSA的密钥长,计算工作量大,而且安全性也不高。题外话,RSA512现在已经可以用普通计算机进行暴力破解了。 然后将公钥复制黏贴进对方机器的 .ssh/authorized_keys 即可,当然你也可以用以下命令进行自动拷贝

1
ssh-copy-id -i eda25519.pub core

NTP

使用chrony portal作为NTP server,提供定时服务给到10.0.2.0/24网段

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
root@portal:~ #-> cat /etc/chrony.conf |grep -v '^#'
erver 0.centos.pool.ntp.org iburst
server 1.centos.pool.ntp.org iburst
server 2.centos.pool.ntp.org iburst
server 3.centos.pool.ntp.org iburst
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
allow 10.0.2.0/24
local stratum 10
logdir /var/log/chrony
log measurements statistics tracking

其他服务器需要将upstream设置为portal

1
2
3
4
5
6
root@grid00:~ #->cat /etc/chrony.conf|grep -v '^#'
server 10.0.2.1 iburst
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
logdir /var/log/chrony

IPA

这个是一个认证服务器,大家可能听说过nis,nisplus,yellowpage,ldap其实本质都是一个东西,只不过扩展性不一样。IPA的话其实底层走的还是ldap那一套,只不过集成了管理界面,对用户更加友好。

server安装

1
ipa-server-install -N --domain-level 0 --allow-zone-overlap --idstart 2000

注意其中的idstart ,根据情况自己修改 安装过程中会提示admin password和directory manager的password 安装过程会提示上游DNS,填10.0.2.1

client安装

以grid00为例

1
ipa-client-install --server=core.ic.X.com --domain=grid00.ic.X.com -N --enable-dns-updates --hostname=grid00.ic.X.com

SSL 证书

在IPA server的安装过程中,会将产生的root CA放在/root/cacert.p12下面,可以用 xca 导入进行管理,以后可以用这个root CA签名新的证书。导入过程中会提示你输入密码,这个密码就是安装过程中输入的admin password。 都已经2024年了,推荐所有的服务都上https

IPA的管理界面默认会占用80/443/8080/8443端口,请避免和其他服务冲突 windows电脑登录的时候会跳出一个认证框,这是因为windows支持kerbose login, 可以通过在 /etc/httpd/conf.d/ipa.conf 里面添加如下配置禁用

1
2
GssapiSessionKey file:/etc/httpd/alias/ipasession.key
BrowserMatch Windows gssapi-no-negotiate

常见操作

增加一个DNS解析

如果你只是想增加一个DNS解析的话,可以使用下面的命令(将gitlab.ic.X.com解析成10.0.2.100)

1
ipa dnsrecord-add ic.X.com. --name gitlab --a-rec 10.0.2.100
缓存刷新

刷新IPA缓存

1
sss_cache -E

刷新系统缓存

1
systemctl restart sssd

DNS 解析

在portal上面安装dnsmasq并指定上游,例如 114 修改所有机器的 /etc/resolv.conf

1
2
search ic.X.com
nameserver 10.0.2.100

这里再次吐槽NetworkManager,默认是会去把这个文件给overwrite掉的,需要做一些额外处理。或者就像我一样,不管三七二十一,直接把NetworkManager给干了。 一个典型的查询场景如下所示,需要注意的是如果查询的域名位于ic.X.com,那直接在core就会返回查询结果。

sequenceDiagram
  participant grid00
  participant core
  participant portal
  participant public_dns
  grid00 ->> core: DNS query for www.baidu.com
  core ->> portal: forward the query
  portal ->> public_dns: forward the query
  public_dns ->> portal: query result for www.baidu.com
  portal ->> core: query result for www.baidu.com
  core ->> grid00: query result for www.baidu.com

netapp

将netapp的目录以NFS的方式挂载到各台机器上,建议挂载分区如下

  • /proj: 项目相关的文件
  • /tools: EDA工具
  • /tmpdir: 临时目录,比如仿真文件等
  • /home: 用户主目录
  • /opt/sge: sungrid的共享目录,其实严格意义上来说只有SGE_CELL那个路径才需要共享,但是都共享了也没太大问题。直接用core分享也可以 需要注意的是netapp默认的nfs4版本会进行root_squash,导致root账号被映射成了nobody,解决办法是在挂载的时候选择用nfs3挂载
1
10.0.2.155:/home                        /home		        nfs 	defaults,async,nosuid,nodev,hard,intr,nfsvers=3,timeo=60,retrans=5 	0 0

netapp如果要关系,需要使用以下命令,要防止主node被backup node给take over掉

1
system node halt -node * -skip-lif-migration-before-shutdown true -ignore-quorum-warnings true -inhibit-takeover true

gcc

系统如果要安装多个gcc版本,建议下载源码解压之后用如下方式进行编译

1
2
3
4
./contrib/download_prerequisites
mkdir build && cd build
../configure --prefix=/tools/misc/gcc/xx.xx.xx --enable-checking=release --enable-languages=c,c++ --enable-threads=posix --disable-multilib --with-system-zlib 
make -j64 && make install

版本之间的切换可以用 modules 进行管理。

sungrid

sungrid是一个开源的集群运算软件,在core上执行

1
yum install -y jemalloc gridengine gridengine-execd gridengine-guiinst gridengine-qmaster gridengine-qmon

然后通过如下命令启动图形安装界面

1
cd /opt/sge && ./start_gui_installer

gitlab

gitlab 是一个可以私有部署的程序员内部交友网站,主要的配置文件是/etc/gitlab/gitlab.rb。 最重要的数据文件推荐放在netapp的存储上面,备份文件建议放在core的本地存储上面,对应的配置如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 git_data_dirs({
   "default" => {
     "path" => "/proj/git"
    }
 })
gitlab_rails['manage_backup_path'] = true
gitlab_rails['backup_path'] = "/data/backup/gitlab"
gitlab_rails['backup_gitaly_backup_path'] = "/opt/gitlab/embedded/bin/gitaly-backup"

 gitlab_rails['backup_keep_time'] = 2592000

对gitlab.rb的内容进行更改之后,需要通过如下命令进行配置刷新

1
gitlab-ctl reconfigure

ssl

要将CA放到 /etc/gitlab/trusted-certs 下面 修改gitlab.rb,关键配置如下

1
2
3
4
nginx['ssl_certificate'] = "/etc/ssl/ic.X.com/server.crt"
nginx['ssl_certificate_key'] = "/etc/ssl/ic.X.com/server.key"
external_url 'https://core.ic.X.com'
nginx['listen_port'] = 1024

可以通过下面的rewrite rule将 https://git.ic.X.com 重定向到 https://core.ic.X.com:1024

1
2
3
4
root@core:~ #-> cat /etc/httpd/conf.d/gitlab-rewrite.conf
# VERSION 6 - DO NOT REMOVE THIS LINE
RewriteEngine on
RewriteRule ^/gitlab        https://core.ic.X.com:1024 [L,R=301]

ldap

修改gitlab.rb.关键配置如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 gitlab_rails['ldap_enabled'] = true
 gitlab_rails['prevent_ldap_sign_in'] = false

 gitlab_rails['ldap_servers'] = {
   'main' => {
    'label' =>  'LDAP',
    'host' => 'core.ic.X.com',
    'port' =>  636,
    'uid' => 'uid',
    'bind_dn' =>  'uid=dummy,cn=users,cn=accounts,dc=ic,dc=X,dc=com',
    'base'  => 'dc=ic,dc=X,dc=com',
    'password' => 'password for dummy',
    'encryption' => 'simple_tls',
    'verify_certificates' => true,
    'smartcard_auth' => false,
    'active_directory' => false,
    'allow_username_or_email_login' => true,
    'lowercase_usernames' => false,
    'block_auto_created_users' => false,
    'user_filter' =>  'memberOf=cn=staff,cn=groups,cn=accounts,dc=ic,dc=X,dc=com',
    'attributes' => {
        'username' => ['uid'],
        'email' => ['Email'],
        'name' => 'cn',
        'first_name' => 'givenName',
        'last_name' => 'sn'
    },
     ## EE only
    'group_base' =>  'cn=groups,cn=accounts,dc=ic,dc=X,dc=com',
    'admin_group' =>  '',
    'sync_ssh_keys' =>  false
   }
 }

配置完之后可以用如下命令进行测试

1
gitlab-rake gitlab:ladap:check

migration

可以用如下的方式进行迁移

  1. 进入旧文件夹,git remote 解除远端reposity的绑定
  2. git remote 添加新远端repository
  3. git push

jenkins

ssl

jenkins用的是java那一套,所以ssl的支持稍微麻烦一点。 CA: update-ca-trust 本身就已经产生了java需要的CA,具体的路径是 /etc/pki/ca-trust/extracted/java/cacerts https证书: 用xca生成p12格式的证书(.pfx),然后用如下命令转换,其中changeit是证书导出的时候设置的密码

1
keytool -importkeystore -srcstorepass changeit -deststorepass changeit -srckeystore ssl.pfx -srcstoretype pkcs12 -destkeystore jenkins.jks -deststoretype JKS

修改配置文件 /usr/lib/systemd/system/jenkins.service,关键配置如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
root@core:~ #-> cat /usr/lib/systemd/system/jenkins.service|grep -v '^#'
#jenkins is picky on java version, must use version 17
Environment="JAVA_HOME=/usr/java/jdk-17.0.5"
Environment="JENKINS_JAVA_CMD=/usr/java/jdk-17.0.5/bin/java"

#load the CA so we can use ldaps 
Environment="JAVA_OPTS=-Djava.awt.headless=true -Djavax.net.ssl.trustStore=/home/jenkins/config/cacerts -Djavax.net.ssl.trustStorePassword=changeit"

#turn off http and enable https
Environment="JENKINS_PORT=-1" 
Environment="JENKINS_HTTPS_LISTEN_ADDRESS=10.0.2.100"
Environment="JENKINS_HTTPS_PORT=8888"

#specify the https ceritificate
Environment="JENKINS_HTTPS_KEYSTORE=/home/jenkins/config/jenkins.jks"
Environment="JENKINS_HTTPS_KEYSTORE_PASSWORD=changeit"

[Install]
WantedBy=multi-user.target

ldap

需要安装ldap插件,/home/jenkins/config.xml 里面的关键配置信息如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<securityRealm class="hudson.security.LDAPSecurityRealm" plugin="ldap@682.v7b_544c9d1512">
    <disableMailAddressResolver>false</disableMailAddressResolver>
    <configurations>
      <jenkins.security.plugins.ldap.LDAPConfiguration>
        <server>ldaps://core.ic.X.com</server>
        <rootDN>dc=ic,dc=X,dc=com</rootDN>
        <inhibitInferRootDN>false</inhibitInferRootDN>
        <userSearchBase>cn=users,cn=accounts</userSearchBase>
        <userSearch>uid={0}</userSearch>
        <groupMembershipStrategy class="jenkins.security.plugins.ldap.FromGroupSearchLDAPGroupMembershipStrategy">
          <filter></filter>
        </groupMembershipStrategy>
        <managerDN>uid=dummy,cn=users,cn=accounts,dc=ic,dc=X,dc=com</managerDN>
        <managerPasswordSecret>{dummy_password_hash}</managerPasswordSecret>
        <displayNameAttributeName>displayname</displayNameAttributeName>
        <mailAddressAttributeName>mail</mailAddressAttributeName>
        <ignoreIfUnavailable>false</ignoreIfUnavailable>
      </jenkins.security.plugins.ldap.LDAPConfiguration>
    </configurations>
    <userIdStrategy class="jenkins.model.IdStrategy$CaseInsensitive"/>
    <groupIdStrategy class="jenkins.model.IdStrategy$CaseInsensitive"/>
    <disableRolePrefixing>true</disableRolePrefixing>
  </securityRealm>

如果因为某些原因导致更改完了登录不了jenkins ( 比如权限忘记配置了),只需要将下面的配置从true改为false即可

1
  <useSecurity>true</useSecurity>

ETX

这是一个服务器登录软件。推荐 EXT ,吊打一切牛鬼蛇神,主要优势有以下几个

  • 只用开放一个端口即可,这样就方便进行管理。vnc这种每个用户都开一个端口的方式一是不方便管理,而是有漏洞,用户要进行脱库操作很容易。
  • 可以对上传下载权限进行单独管理,一般只允许上传,不允许下载
  • 可以限制从服务器到本地复制黏贴的字符个数,有效的防止了用户通过CTRL+C CTRL+V 的方式拷贝代码到本地
  • 集成ldap认证,可对用户登录以及可见的profile做限制 当然他的缺点也是显而易见的,那就是需要花钱购买。这公司的销售人员也是非常了解国情,默认都是提供买断的license服务,一次购买,终身可用,然后单个license的价格还是不便宜。

server

建议安装在core上面,然后通过端口映射的方式映射到portal的8443端口

node

建议安装在portal上面,默认端口是5510 添加node的时候选择10.0.2.1,端口5510,然后再client IP里面进行重映射,比如192.168.5.100:5510

ssl

如果要增加ssl支持,需要修改 $INSTALL_DIR/data/ssl 里面的 server.keyserver.crt. 可以用前文提到的xca工具生成,懒人的话建议生成通配符证书即可。 另外其实在linux上面做ETX的多开很容易,文件夹复制黏贴改个名字就行了。Windows node 复制黏贴比较麻烦,暂时还没有花精力去搞。至于为何要多开?那当然是解决license个数不足的问题了。

flexlm

几乎所有的eda工具都是用flexlm来管理的,这个和谐方式也是各式各样。有一些注意事项

  1. 允许在同一个端口上起多个vendor的license daemon,比如你可以把不同家的license文件里面的端口都改成一样的,然后lmgrd一起启动
  2. 一些和谐版的license daemon会有相互打架的情况,所以1的前提就不成立了
  3. 有些vendor daemon对网卡名字有特别要求,一定要求是 eth 开头,比如TSMC
  4. license文件可以进行复制操作,比如你只买了10个正版license,如何扩展成100个,土鳖一点的方法就是用虚拟机多开,修改MAC地址。但是其实不用这么麻烦的,你在一台机器上也有办法实现开N个相同的vendor daemon的。 由于可能不是那么众所周知的原因,宝岛台湾的一些工具是不使用flexlm管理的。个人推测一方面是成本考虑,另一方面是因为他们知道flexlm的license很容易被和谐,又不像大厂可以承受被破解的代价,所以就自己开发了一套软件授权管理工具。

mirror

在core上面设置centos的mirror,portal通过rsync的方式将外部的mirror同步到core上 一个简单的用perl写的同步脚本如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/usr/bin/perl
use strict;
use warnings;

my $lock_file = "/run/lock/subsys/repo_rsync";

exit if -e $lock_file;

#Set the PATH
$ENV{'PATH'} = "/bin:/usr/bin:/sbin";

system("touch $lock_file");

my $base_path = "/repo/centos";
my $version   = "7.9.2009";
my @parts     = qw ( centosplus os updates extras contrib epel );
#my @parts     = qw ( epel );

#Invoke the rsync to update the repo
#For rpmforge, use this one rsync://ftp-stud.fht-esslingen.de/dag
foreach (@parts) {
    next if $_ eq 'contrib';
    if ( $_ eq 'epel' ) {
        system( "rsync -avSHP --exclude 'debug' --exclude 'repodata' --exclude 'repoview' --delete --delete-excluded rsync://mirror.sjtu.edu.cn/fedora/epel/7/x86_64/ $base_path/$version/$_/x86_64/Packages/");
    }else {
        #system( "rsync -avSHP --delete rsync.mirrors.ustc.edu.cn::repo/centos/$version/$_/x86_64/Packages/ $base_path/$version/$_/x86_64/Packages/");
        #update: need to remove the repo prefix
        system( "rsync -avSHP --delete rsync.mirrors.ustc.edu.cn::centos/$version/$_/x86_64/Packages/ $base_path/$version/$_/x86_64/Packages/");
    }
}

#Invoke createrepo
foreach (@parts) {
    system("ssh core createrepo --workers 16 $base_path/$version/$_/x86_64");
}

unlink $lock_file;

在core上面讲mirror通过https的形式提供给其他人,具体的方法如下

1
2
3
4
5
6
7
root@core: #-> cat /etc/httpd/conf.d/repo.conf
Alias /centos "/repo/centos"
<Directory  /repo/centos>
    Options Indexes FollowSymLinks MultiViews
    AllowOverride all
    Require all granted
</Directory>

最后修改机器的更新源为core

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
root@core: #-> cat /etc/yum.repos.d/local.repo
[local-base]
name=local-$releasever - Base
baseurl=https://core.ic.X.com/centos/$releasever/os/$basearch/
gpgkey=https://core.ic.X.com/centos/$releasever/RPM-GPG-CentOS-7
gpgcheck=1
enabled=1

[local-updates]
name=local-$releasever - Updates
baseurl=https://core.ic.X.com/centos/$releasever/updates/$basearch/
gpgkey=https://core.ic.X.com/centos/$releasever/RPM-GPG-CentOS-7
gpgcheck=1
enabled=1

[local-extras]
name=local-$releasever - Extras
baseurl=https://core.ic.X.com/centos/$releasever/extras/$basearch/
gpgkey=https://core.ic.X.com/centos/$releasever/RPM-GPG-CentOS-7
gpgcheck=1
enabled=1

[local-centosplus]
name=local-$releasever - Plus
baseurl=https://core.ic.X.com/centos/$releasever/centosplus/$basearch/
gpgkey=https://core.ic.X.com/centos/$releasever/RPM-GPG-CentOS-7
gpgcheck=1
enabled=1

[local-contrib]
name=local-$releasever - Contrib
baseurl=https://core.ic.X.com/centos/$releasever/contrib/$basearch/
gpgcheck=0
enabled=1

[local-epel]
name=local-$releasever - Epel
baseurl=https://core.ic.X.com/centos/$releasever/epel/$basearch/
gpgcheck=0
enabled=1

安全设置

selinux

这个东西很好,但是也很麻烦,如果不是很会折腾,建议关闭:

编辑 /etc/sysconfig/selinux, 将里面的SELINUX更改成disabled,然后重启

ssh限制

需要在/etc/ssh/sshd_config里面做如下配置

  • 普通用户关闭ssh登录权限
  • 打开core上的git登录权限,这是为了使用ssh进行git的checkout
  • 只允许基于ssh key的登录方式,这是为了防止MTIM攻击

防火墙配置

内网的机器可以把防火墙都关掉
portal上面的防火墙只开放必要的端口,INPUT/OUTPUT/FORWARD的policy都设置成DROP
portal作为登录机器是不允许跑EDA软件的,所以在core的防火墙上面要阻止来自portal的license请求
另外需要注意虚拟机的网络是不受iptables控制的,所以在portal上绝对绝对不要装虚拟机软件,不让网络无法管控

ETX 配置

限制最大拷贝数

profile -> general -> optional settings 里面添加如下配置(最大只允许拷贝512个字符)

1
proxy.AllowCopyFromX=512

限制用户编辑profile

如果允许用户自己编辑profile,他就可以设置一个profile允许上传和下载,这无疑是有问题的

邮件发送

jenkins/gitlab等都有发送邮件的需求,但是core本身是无法连接外网的,解决方法就是要借助core 需要有一个专门的邮件账号用来发邮件(jarvis),这个账号只能开放smtp功能,不能开放 imap功能,这主要是为了防止有用户发完邮件又通过imap将发送邮件删除,从而销毁证据
具体步骤如下

  1. 在portal上面开一个邮件代理,只允许特定IP连接本地的465端口
  2. 在core上,只有特定用户才可以连接到core的465端口,包括以下用户
    1. ETX 服务: root
    2. jenkins服务: jenkins
  3. 上面两个步骤是确保用户无法使用自己的邮箱发送邮件,而只能通过jarvis账号发送
  4. jarvis账号会将所有内容存档,便于安全审计 邮件代理可以用nginx处理,关键配置如下
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
root@portal0:~ #-> cat /etc/nginx/stream/mail_pro.conf
upstream mailsmtp_pro {
       server smtp.qiye.aliyun.com:465;
}

server {
       listen 465;
       proxy_connect_timeout 5s;
       proxy_timeout 5s;
       proxy_pass mailsmtp_pro;
}

目录夹权限

下面这些文件夹需要设置合适的权限保证普通用户无法看到

  • /proj/git: 里面存放了git的database
  • /proj/xxx: 只有处于项目组xxx里面的人才能进入
  • /data/backup: 需要保证普通用户无法访问备份文件夹
Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 StackJimmy 设计