配置我的Ubuntu Server记

2013年06月23日

跟老板申请买了一台配置相对较好的计算机回来做GPU计算,当然,不能独享,所以做成服务器让大家都来用。

这篇日志用来记录配置过程中遇到的一些问题,以方便下次不需要到处谷歌度娘。

安装Server版系统

我使用的是最新版的Ubuntu Server 13.04 64bit版,这个安装好不表。

# 配置好中文显示的问题
sudo sed -e '$a\LANG="zh_CN.UTF-8"' -e '$a\LANGUAGE="zh_CN:zh:en_US:en"' -i /etc/environment
sudo sed -n -e '1 i\LANG="zh_CN.UTF-8"' -e 'a\LANGUAGE="zh_CN:zh:en_US:en"' -i /etc/default/locale
sudo sed '1 i\zh_CN.UTF-8 UTF-8' -i /var/lib/locales/supported.d/local
sudo apt-get install language-pack-zh-hans fcitx ttf-wqy-microhei && fc-cache -fv && sudo locale-gen
# 安装一些常用的软件
sudo apt-get install --no-install-recommends tint2 tilda feh scrot thunar mercurial zip unzip unrar p7zip mupdf

配置桌面及VNC

SSH当然是少不了的,虽说我基本上能在CLI下工作,但是考虑到其他人也要用且GUI确实也有要使用到的时候,所以再装上一个简单的OpenBox窗口管理器和VNC。

sudo apt-get install --no-install-recommends xorg openbox vnc4server openssh-server

运行命令vnc4server来配置VNC服务,配置成功后去~/.vnc/xstartup去掉下面两行的注释:

# Uncomment the following two lines for normal desktop:
unset SESSION_MANAGER
exec /etc/X11/xinit/xinitrc

为了使开机时VNC服务就启动,可以创建可执行脚本/etc/init.d/vncserversudo chmod +x /etc/init.d/vncserver),并在/etc/rc.local中添加/etc/init.d/vncserver start在开机时启动服务。

#!/bin/sh -e

# The Username:Group that will run VNC
export USER="nick"

# Color depth (between 8 and 32)
# DEPTH="32"

# The display that VNC will use
DISPLAY="1"

# The Desktop geometry to use.
#GEOMETRY="800x600"
GEOMETRY="1024x768"
#GEOMETRY="1280x1024"

# The name that the VNC Desktop will have.
NAME="my-vnc-server"

# OPTIONS="-name ${NAME} -depth ${DEPTH} -geometry ${GEOMETRY} :${DISPLAY}"
OPTIONS="-name ${NAME} -geometry ${GEOMETRY} :${DISPLAY}"

case "$1" in
start)
su ${USER} -c "/usr/bin/vncserver ${OPTIONS}"
;;

stop)
su ${USER} -c "/usr/bin/vncserver -kill :${DISPLAY}"
;;

restart)
$0 stop
$0 start
;;
esac

exit 0

注意,上面脚本中有一个变量叫${DISPLAY},这是使用的显示器,因为我的服务器没有显示器,直接设为1就好了,当然,也可以在不同的${DISPLAY}多开启几个VNC服务。同时,这也是VNC服务使用的编号和端口号,在VNC客户端填写服务器时需要加上端口号,如IP:1

如果要使计算机启动后自动进入tty1而非GUI的tty7,可以修改/etc/inittab/etc/init/rc-sysinit.conf中的DEFAULT_RUNLEVEL为3。

虽然服务器上不一定有音视频设备,但是我还是惯例添加我的用户到video/audio组以使得摄像头,耳机能正常工作。

sudo adduser nick video
sudo adduser nick audio

安装CUDA

然后就是去Nvidia下载驱动,去CUDA engCUDA chs下载CUDA。

将以下内容添加到文件/etc/modprobe.d/blacklist-nouveau.conf以禁用系统默认驱动nonveau

blacklist nouveau
blacklist lbm-nouveau
options nouveau modeset=0
alias nouveau off
alias lbm-nouveau off

然后sudo update-initramfs -u更新内核并重启。

安装驱动前需要关闭X服务器。现在一般都是用的lightdm管理X服务,sudo service lightdm stop停掉它,VNC服务也是需要开启X服务的,所以先以命令vnc4server -kill :1关闭之。然后sudo sh NVIDIA-Linux-x86_64-***.run安装驱动,sudo sh cuda_***.run安装CUDA。注意,安装CUDA时不需要选择安装驱动。

安装CUDA samples时若不成功,查看安装日志会发现提示缺少libglut.so,先安装之然后建立一个软链接到需要它的位置

sudo apt-get install --no-install-recommends freeglut3-dev
sudo ln -s /usr/lib/x86_64-linux-gnu/libglut.so /usr/lib/libglut.so

再重新安装CUDA就没问题了。重启后可以先去编译一下项目~/NVIDIA_CUDA-5.0_Samples/1_Utilities/deviceQuery,查看一下自己GPU是否能正确识别,以及其参数。

配置多软件版本共存

最新的CUDA5.5要求GCC版本不能高于4.7,所以编译项目时可能出现提示GCC版本过高。可以同时安装gcc-4.6,并设置包冲突来解决。

# 安装低版本的包
sudo apt-get install --no-install-recommends gcc-4.6 g++-4.6
# 设置冲突项
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.6 100
sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-4.7 50

sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.6 100
sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.7 50

这样,就为两个版本设置了包冲突。注意到,命令最后有个数值,这是用来表示优先级的,越大优先级越高。还可以通过以下命令来手动切换版本:

sudo update-alternatives --config gcc

配置NTP服务

服务器上的时间和客户端时间有可能不一致,这将导致诸如make命令执行时提示时间错误。可以利用在服务器上启用ntp时间同步服务来解决这个问题。sudo apt-get install ntp安装服务程序,然后修改/etc/ntpd.conf文件,可以去掉注释或添加以下内容让服务器在没有和上游保持同步时将本机之间提供给客户端

server 127.127.1.0
fudge 127.127.1.0 stratum 8 

sudo service ntp restart重启服务等待几分钟让ntp服务生效。可以利用命令watch ntpq -p查看是否服务已生效,当reach一列至少达到17后服务基本上就生效了。在客户端上采用命令ntpdate server-address定期更新时间或同样配置ntp服务并添加服务器为上游。ntp服务采用udp端口123,记得在防火墙和路由上打开。

配置NFS服务

接下来,为了能方便地互相访问文件,有必要做一个远程目录映射,一种方法是采用SSHFS做映射,另一种是采用NFS做映射。考虑到SSHFS会有一段时间后掉线的问题,所以我用了NFS系统。

# server端
sudo apt-get install nfs-kernel-server
# 添加需要共享的目录(由/etc/exports管理)
sudo sh -c "echo '/usr *(insecure,rw,sync,no_root_squash)' >> /etc/exports"
# 或
echo '/usr *(insecure,rw,sync,no_root_squash)' | sudo tee -a /etc/exports
# 重启服务
sudo  /etc/init.d/nfs-kernel-server restart

# client端
sudo apt-get install nfs-common
# 挂载
sudo mount IP:/dir /dest.dir

关于/etc/exports文件的写法,

共享目录 允许访问主机(选项)

----共享目录----
必须使用绝对路径,而不能使用符号链接。

----允许访问的主机----
单个机器:一个全限定域名(能够被服务器解析)、主机名(能够被服务器解析)或IP地址。
使用通配符来指定的机器系列,使用 * 或 ?字符来指定一个字符串匹配。IP地址中不使用通配符。如果反向DNS查询失败,它们可能会碰巧有用。在完整域名中指定通配符时,点(.)不包括在通配符中。例如,*.example.com包括one.example.com,但不包括one.two.example.com.。
IP网络:使用a.b.c.d/z,a.b.c.d是网络,z是子网掩码中的位数(如192.168.0.0/24)。另一种可以接受的格式是a.b.c.d/netmask,a.b.c.d是网络,netmask是子网掩码(如192.168.70.8/255.255.255.0)。

----设置选项----
insecure: 关闭安全选项,否者当客户端的连接端口大于1024时将拒绝连接,而跨路由器的时候端口一般都大于1024。
rw:可读写权限。
ro:只读权限。
no_root_squash:当登录NFS主机使用共享目录的使用者是root时,其权限将被转换成为匿名使用者,通常它的UID与GID都会变成nobody身份。
root_squash;如果登录NFS主机使用共享目录的使用者是root,那么对于这个共享的目录来说,它具有root的权限。
all_squash:忽略登录NFS使用者的身份,其身份都会被转换为匿名使用者,通常即nobody。
anonuid:通常为nobody,也可以自行设定这个UID的值,UID必须存在于/etc/passwd中。
anongid:同anonuid,但是变为Group ID。
sync:同步写入资料到内存与硬盘中。
async:资料会先暂存于内存中,而非直接写入硬盘。

nfs一个麻烦的地方是如果掉线了要想卸载它很麻烦,下面是一些方法:

  1. umount加参数f,是强制执行umount
  2. 要kill正在使用这个目录的进程。可以fuser -m -v nfsfs看一下哪个用户哪个进程占用着此设备, 然后杀掉fuser -m -v -k nfsfs占用此设备的进程(fuser -m -v -k -i nfsfs杀掉之前先确认)。 更简单地直接用fuser -km nfsfs杀掉所有以任何形式访问文件系统nfsfs的进程。杀完之后umount就行了。
  3. umount -l nfsfs,采用Lazy方式卸载。

对于一个频繁掉线的nfs,用soft模式可以避免系统无法响应不断重试。

sudo mount -o soft IP:/medis/study /media/office/

使用nfs系统的客户端要求和服务器端有相同的uid和gid,如果不同,可以在服务器端将被导出用户转为为匿名用户并开启all_squash后导出

/your/export/dir *(rw,sync,all_squash,no_subtree_check,anonuid=1000,anongid=1000)

配置cgroup资源管理服务

组内人越来越多,老板又新配了两台小型工作站,需要限制一下大家各自的CPU使用个数,这可以通过cgroup服务1来实现。 可以通过创建一个临时的资源组来限制特定pid的程序:

# create one resource group
sudo cgcreate -g cpu:/temp_restrict
# restrict the cpu into 10 000/1 000 000 = 1%
echo 10000 |sudo tee /cgroup/cpu/temp_restrict/cpu.cfs_quota_us
# select PIDs owned by user and restrict them
ps aux|awk '/^user/{print "echo "$2" >> /cgroup/cpu/temp_restrict/tasks"}'|sudo sh 
# delete the resource group
sudo cgdelete cpu:/temp_restrict

通常使用配置文件来管理cgroup,下面贴出我的配置文件和参数解释:

#在/etc/cgconfig.conf文件中添加资源组信息
group maxcpu{ #资源通过树形层级结构管理,组是叶子节点,说明该节点下资源限制情况
        perm{ #设置此组相关权限
                task{ #可以在此组下执行程序的用户及用户组
                        uid = nick; #用户
                        gid = nick; #用户组
                }
                admin{ #可以管理此组的用户或用户组
                        uid = root;
                        gid = root;
                }
        }
        cpu{ #限制cpu资源子系统
                cpu.cfs_period_us = 100000; #cpu资源的统计周期,默认100ms
                cpu.cfs_quota_us = 50000; #每个统计周期下可以实际使用的时间
                cpu.shares = 1; #此任务组的cpu利用时间比例,总比例是所有同一层级group的总和
        }
        cpuset{

                cpuset.cpus="0-5"; #分配给该组的cpu核编号
        }

}

#在/etc/cgrules.conf文件中设置自动移动任务到队列的策略
@nick   cpu   maxcpu #对nick组用户的cpu资源执行maxcpu策略
nick    cpu   maxcpu #对nick用户的cpu资源执行maxcpu策略

cgconfig.conf文件中的内容可分开存放到目录/etc/cgconfig.d下。 各项参数文档请参考红帽企业版Linux 6资源管理指南。配置好后重启服务cgconfigcgred即可生效。

注意:

  1. centos的libcgroup-0.37-7.1.el6_4.x86_64包是有bug的,其cgred服务无法正常启动。通过rpm -q libcgroup可查看软件版本,对有问题的版本可用命令yum downgrade libcgroup-0.37-4.el6降级或用yum install libcgroupoup-0.40.rc1-12.el6.x86_64升级到新版本。