Tim*_*yan 4 xfce amazon-ec2 amazon-emr emr
我需要运行一个需要GUI界面来启动和配置的应用程序.我还需要能够在亚马逊的EC2服务和EMR服务上运行此应用程序.EMR要求意味着它必须在亚马逊的Linux AMI上运行.
经过广泛搜索后,我一直无法找到任何现成的解决方案,特别是要求在亚马逊的AMI上运行.最接近的匹配和最常引用的解决方案在这里.不幸的是,它是在RHEL6实例上开发的,该实例与亚马逊的AMI有足够的不同,该解决方案不起作用.
我在下面发布我的解决方案.希望它可以节省一些其他人用于提出正确配方所需的数小时实验.
Tim*_*yan 12
这是我在亚马逊的AMI上运行GUI的解决方案.我用这篇文章作为起点,但不得不进行许多修改才能让它在亚马逊的AMI上运行.我还添加了额外的信息,以便以合理自动化的方式完成这项工作,因此需要不止一次启动此环境的个人可以毫不费力地完成这项工作.
注意:我在这篇文章中包含了很多评论.我提前道歉,但我认为如果他们能够理解为什么在此过程中做出各种选择,那么需要进行修改的人可能会有所帮助.
下面包含的脚本会沿途安装一些文件.有关这些脚本使用的文件和目录结构的列表,请参阅第4节.
执行'yum update'后,大多数解决方案都包含类似的行
sudo yum groupinstall -y "Desktop"
这个欺骗性的简单步骤需要在Amazon AMI上付出更多努力.此组未在Amazon AMI中配置(AAMI从此处开始).AAMI默认安装并启用了亚马逊自己的存储库.还安装了epel repo,但默认情况下禁用它.启用epel后,我找到了桌面组,但没有填充包.我还发现了填充的Xfce(另一种桌面替代品).最终我决定安装Xfce而不是Desktop.尽管如此,这并不是直截了当的,但它最终导致了解决方案.
这里值得注意的是,我尝试的第一件事就是安装centos存储库并从那里安装Desktop组.最初这看起来很有希望.该小组完全填充了包裹.但是,经过一番努力,我最终确定在AAMI上已经安装的依赖项和软件包之间存在太多的版本冲突.
这导致我从epel repo中选择Xfce.由于epel repo已经安装在AAMI上,我认为与Amazon repos的依赖版本协调会更好.这通常是正确的.在epel repo或Amazon repos中发现了许多依赖项.对于那些没有的,我能够在centos repo中找到它们,并且在大多数情况下那些是叶依赖性.因此,大多数问题来自于centos repo中的少数依赖项,这些依赖项具有与亚马逊或epel repo冲突的子依赖项.最后,需要一些黑客来绕过依赖冲突.我试图尽可能地减少这些.这是安装Xfce的脚本
installGui.sh
#!/bin/bash
# echo each command
set -x
# assumes RSRC_DIR and IS_EMR set by parent script
YUM_RSRC_DIR=$RSRC_DIR/yum
sudo yum -y update
# Most info I've found on installing a GUI on AWS suggests to install using
#> sudo yum groupinstall -y "Desktop"
# This group is not available by default on the Amazon Linux AMI.  The group
# is listed if the epel repo is enabled, but it is empty.  I tried installing
# the centos repo, which does have support for this group, but it simply end
# up having to many dependency version conflicts with packages already installed
# by the Amazon repos.
#
# I found the path of least resistance to be installing the group Xfce from
# the epel repo. The epel repo is already included in amazon image, just not enabled.
# So I'm guessing there was at least some consideration by Amazon to align
# the dependency versions of this repo with the Amazon repos.
#
# My general approach to this problem was to start with the last command:
#> sudo yum groupinstall -y Xfce
# which will generate a list of missing dependencies.  The script below
# essentially works backwards through that list to eliminate all the
# missing dependencies.
#
# In general, many of the dependencies required by Xfce are found in either
# the epel repo or the Amazon repos.  Most of the remaining dependencies can be
# found in the centos repo, and either don't have any further dependencies, or if they
# do those dependencies are satisfied with the centos repo with no collisions
# in the epel or amazon repo.  Then there are a couple of oddball dependencies
# to clean up.
# if yum-config-manager is not found then install yum-utils
#> sudo yum install yum-utils
sudo yum-config-manager --enable epel
# install centos repo
# place the repo config @  /etc/yum.repos.d/centos.repo
sudo cp $YUM_RSRC_DIR/yum.repos.d/centos.repo /etc/yum.repos.d/
# The config centos.repo specifies the key with a URL.  If for some reason the key
# must be in a local file, it can be found here: https://www.centos.org/keys/RPM-GPG-KEY-CentOS-6
# It can be installed to the right location in one step:
#> wget -O /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6 https://www.centos.org/keys/RPM-GPG-KEY-CentOS-6
# Note, a key file must also be installed in the system key ring.  The docs are a bit confusing
# on this, I found that I needed to run both gpg AND then followed by rpm, eg:
#> sudo gpg --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
#> sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
# I found there are a lot of version conflicts between the centos, Amazon and epel repos.
# So I did not enable the centos repo generally.  Instead I used the --enablerepo switch
# enable it explicitly for each yum command that required it.  This only works for yum.  If
# rpm must be used, then yum-config-manager must be used to enable/disable repos as a
# separate step.
#
# Another problem I ran into was yum installing the 32-bit (*.i686) package rather than
# the 64-bit (*.x86_64) verision of the package.  I never figured out why.  So I had
# to specify the *.x86_64 package explicitly.  The search tools (eg. 'whatprovides')
# did not list the 64 bit package either even though a manual search through the
# package showed the 64 bit components were present.
#
# Sometimes it is difficult to determine which package must be in installed to satisfy
# a particular dependency.  'whatprovides' is a very useful tool for this
#> yum --enablerepo centos whatprovides libgdk_pixbuf-2.0.so.0
#> rpm -q --whatprovides libgdk_pixbuf
sudo yum --enablerepo centos install -y gdk-pixbuf2.x86_64
sudo yum --enablerepo centos install -y gtk2.x86_64
sudo yum --enablerepo centos install -y libnotify.x86_64
sudo yum --enablerepo centos install -y gnome-icon-theme
sudo yum --enablerepo centos install -y redhat-menus
sudo yum --enablerepo centos install -y gstreamer-plugins-base.x86_64
# problem when we get to libvte, installing libvte requires expat, which conflicts with amazon lib
# the centos package version was older and did not install right lib version
# but … the expat dependency was coming from a dependency on python-libs.
# the easiest workaround was to install python using the amazon repo, that in turn
# installs a version of python libs that is compatible with the version of libexpat on the system.
sudo yum install -y python
sudo yum --enablerepo centos install -y vte.x86_64
sudo yum --enablerepo centos install -y libical.x86_64
sudo yum --enablerepo centos install -y gnome-keyring.x86_64
# another sticky point, xfdesktop requires desktop-backgrounds-basic, but ‘whatprovides’ does not 
# provide any packages for this query (not sure why).  It turns out this is provided by the centos 
# repo, installing ‘desktop-backgrounds-basic’ will try to install the package redhat-logos, but 
# unfortunately this is obsoleted by Amazon’s generic-logos package
# The only way I could find to get around this was to erase the generic logos package.
# This doesn't seem too risky since this is just images for the desktop and menus.
#
sudo yum erase -y generic-logos
# Amazon repo must be disabled to prevent interference with the install
# of redhat-logos
sudo yum --disablerepo amzn-main --enablerepo centos install -y redhat-logos
# next problem is a dependency on dbus.  The dependency comes from dbus-x11 in 
# centos repo.  It requires dbus version 1.2.24, the amazon image already has
# version 1.6.12 installed.  Since the dbus-x11 is only used by the GUI package,
# easiest way around this is to install dbus-x11 with no dependency checks.
# So it will use the newer version of dbus (should be OK).  The main thing that could be a problem
# here is if it skips some other dependency.  When doing manually, its possible to run the install until
# the only error left is the dbus dependency.  It’s a bit risky running in a script since, basically it’s assuming
# all the dependencies are already in place.
yumdownloader --enablerepo centos dbus-x11.x86_64
sudo rpm -ivh --nodeps dbus-x11-1.2.24-8.el6_6.x86_64.rpm
rm dbus-x11-1.2.24-8.el6_6.x86_64.rpm
sudo yum install -y xfdesktop.x86_64
# We need the version of poppler-glib from centos repo, but it is found in several repos.
# Disable the other repos for this step.
# On EMR systems a newer version of poppler is already installed.  So move up 1 level
# in dependency chain and force install of tumbler.
if [ $IS_EMR -eq 1 ]
then
    yumdownloader --enablerepo centos tumbler.x86_64
    sudo rpm -ivh --nodeps tumbler-0.1.21-1.el6.x86_64.rpm
else
    sudo yum --disablerepo amzn-main --disablerepo amzn-updates --disablerepo epel --enablerepo centos install -y poppler-glib
fi
sudo yum install  --enablerepo centos -y polkit-gnome.x86_64
sudo yum install  --enablerepo centos  -y control-center-filesystem.x86_64
sudo yum groupinstall -y Xfce
以下是centos存储库配置文件的内容:
centos.repo
[centos]
name=CentOS mirror
baseurl=http://repo1.ash.innoscale.net/centos/6/os/x86_64/
failovermethod=priority
enabled=0
gpgcheck=1
gpgkey=https://www.centos.org/keys/RPM-GPG-KEY-CentOS-6
如果您需要的只是在Amazon AMI上安装桌面软件包的方法,那么您就完成了.本文的其余部分介绍了如何配置VNC以通过SSH隧道访问桌面,以及如何打包所有这些以便可以从脚本轻松启动实例.
下面是我安装GUI的顶级脚本.配置几个变量后,它首先要做的是从上面的步骤1调用脚本.这个脚本有一些额外的包袱,因为我已经构建它以在常规的ec2实例上工作,或者emr以及root或ec2-user.基本步骤是
需要注意的几个要点:
这假设您将通过SSH隧道访问VNC服务器.最后,这似乎是最简单,最可靠的安全方式.由于您可能在安全组规范中打开了SSH端口,因此您无需对其进行任何更改.此外,VNC客户端/服务器的加密配置并不简单.错误似乎很容易让你的通讯不加密.其设置位于vncservers文件中.-localhost开关告诉vnc只接受本地连接.'-nolisten tcp'告诉关联的xserver模块也不接受来自网络的连接.最后,'-SecurityTypes None'开关允许您在不键入passwd的情况下打开VNC会话,因为进入机器的唯一方法是通过ssh,
xstartup文件确定第一次启动VNC会话时将启动的内容.我注意到很多关于这个主题的帖子都跳过了这一点.如果你没有告诉它启动Xfce桌面,你将在启动VNC时得到一个空白窗口.我在这里的配置非常简单.
尽管我上面提到VNC服务器配置为不提示输入密码,但它仍然需要.vnc目录中的passwd文件才能启动服务器.第一次运行脚本时,它会在尝试启动服务器时失败.通过ssh登录计算机并运行"vncpasswd".它将在.vnc目录中创建一个passwd文件,您可以将其保存为在安装期间作为这些脚本的一部分使用.注意,我已经读过VNC没有做任何复杂的事情来保护passwd文件.因此,我不建议使用您用于其他更重要帐户的密码.
installGui.sh
#!/bin/bash
# echo each command
set -x
BIN_DIR="${BASH_SOURCE%/*}"
ROOT_DIR=$(dirname $BIN_DIR)
RSRC_DIR=$ROOT_DIR/rsrc
VNC_DIR=$RSRC_DIR/vnc
# Install user config files into ec2-user home directory
# if it is available.  In practice, this should always
# be true
if [ -d "/home/ec2-user" ]
then
   USER_ACCT=ec2-user
else
   USER_ACCT=hadoop
fi
HOME_DIR="/home"
# Use existence of hadoop home directory as proxy to determine if
# this is an EMR system.  Can be used later to differentiate
# steps on EC2 system vs EMR.
if [ -d "/home/hadoop" ]
then
    IS_EMR=1
else
    IS_EMR=0
fi
# execute Xfce desktop install
. "$BIN_DIR/installXfce.sh"
# now roughly follow the following from step 3: https://devopscube.com/setup-gui-for-amazon-ec2-linux/
sudo yum install -y pixman pixman-devel libXfont
sudo yum -y install tigervnc-server
# install the user account configuration file.
# This setup assumes the user will always connect to the VNC server
# through an SSH tunnel.  This is generally more secure, easier to
# configure and easier to get correct than trying to allow direct
# connections via TCP.
# Therefore, config VNC server to only accept local connections, and
# no password required.
sudo cp $VNC_DIR/vncservers-$USER_ACCT /etc/sysconfig/vncservers
# install the user account, vnc config files
sudo mkdir $HOME_DIR/$USER_ACCT/.vnc
sudo chown $USER_ACCT:$USER_ACCT $HOME_DIR/$USER_ACCT/.vnc
# need xstartup file to tell vncserver to start the window manager
sudo cp $VNC_DIR/xstartup $HOME_DIR/$USER_ACCT/.vnc/
sudo chown $USER_ACCT:$USER_ACCT $HOME_DIR/$USER_ACCT/.vnc/xstartup
# Even though the VNC server is config'd to not require a passwd, the
# server still looks for the passwd file when it starts the session.
# It will fail if the passwd file is not found.
# The first time these scripts are run, the final step will fail.
# Then manually run
#> vncpasswd
# It will create the file ~/.vnc/passwd.  Then save this file to persistent
# storage so that it can be installed to the user account during
# server initialization.
sudo cp $ROOT_DIR/home/user/.vnc/passwd $HOME_DIR/$USER_ACCT/.vnc/
sudo chown $USER_ACCT:$USER_ACCT $HOME_DIR/$USER_ACCT/.vnc/passwd
# This script will be running as root if called from the EC2 launch
# command.  VNC server needs to be started as the user that
# you will connect to the server as (eg. ec2-user, hadoop, etc.)
sudo su -c "sudo service vncserver start" -s /bin/sh $USER_ACCT
# how to stop vncserver
# vncserver -kill :1
# On the remote client
# 1. start the ssh tunner
#> ssh -i ~/.ssh/<YOUR_KEY_FILE>.pem -L 5901:localhost:5901 -N ec2-user@<YOUR_SERVER_PUBLIC_IP>
#    for debugging connection use -vvv switch
# 2. connect to the vnc server using client on the remote machine.  When
#    prompted for the IP address, use 'localhost:5901'
#    This connects to port 5901 on your local machine, which is where the ssh
#    tunnel is listening.
VNCSERVERS
# The VNCSERVERS variable is a list of display:user pairs.
#
# Uncomment the lines below to start a VNC server on display :2
# as my 'myusername' (adjust this to your own).  You will also
# need to set a VNC password; run 'man vncpasswd' to see how
# to do that.  
#
# DO NOT RUN THIS SERVICE if your local area network is
# untrusted!  For a secure way of using VNC, see this URL:
# http://kbase.redhat.com/faq/docs/DOC-7028
# Use "-nolisten tcp" to prevent X connections to your VNC server via TCP.
# Use "-localhost" to prevent remote VNC clients connecting except when
# doing so through a secure tunnel.  See the "-via" option in the
# `man vncviewer' manual page.
# Use "-SecurityTypes None" to allow session login without a password.
# This should only be used in combination with "-localhost"
# Note: VNC server still looks for the passwd file in ~/.vnc directory
# when the session starts regardless of whether the user is
# required to enter a passwd.
# VNCSERVERS="2:myusername"
# VNCSERVERARGS[2]="-geometry 800x600 -nolisten tcp -localhost"
VNCSERVERS="1:ec2-user"
VNCSERVERARGS[1]="-geometry 1280x1024 -nolisten tcp -localhost -SecurityTypes None"
的xstartup
#!/bin/sh
unset SESSION_MANAGER
unset DBUS_SESSION_BUS_ADDRESS
# exec /etc/X11/xinit/xinitrc
/usr/share/vte/termcap/xterm &
/usr/bin/startxfce4 &
Once you've got the VNC server running on EC2 you can try connecting to it. First open an SSH tunnel to your instance. 5901 is the port where the VNC server listens for display 1 from the vncservers file. It will listen for display 2 on port 5902, etc. This command creates a tunnel from port 5901 on your local machine to port 5901 on the instance.
ssh -i ~/.ssh/<YOUR_KEY_FILE>.pem -L 5901:localhost:5901 -N ec2-user@<YOUR_SERVER_PUBLIC_IP>
Now open your preferred VNC client. Where it prompts for the IP address of the server enter:
localhost:5901
If nothing happens at all, then either there was a problem starting the vnc server, or there is a connectivity problem preventing the client from reaching the server, or possibly a problem in vncservers config file
If a window comes up, but it is just blank then check that the Xfce install completed successfully and that the xstartup file is installed.
If you just need to do this once then sftp'ing the scripts over to your instance and running manually is fine. Otherwise you're going to want to automate this as much as possible to make it faster and less error prone when you do need to fire up an instance with a GUI.
The first step to automating is to create an EFS volume containing the scripts and config files that can be mounted when the instance is started. Amazon has plenty of info on creating a network file system. A couple points to pay attention to when creating the volume. If you don't want your volume to be open to the world you may want to create a custom security group to use for your EFS volume. I created security group for my EFS volume (call it NFS_Mount) that only allows inbound TCP traffic on port 2049 coming from one of my other security groups, call it MasterVNC. Then when you create an instance, make sure to associate the MasterVNC security group with that instance. Otherwise the EFS volume won't allow your instance to connect with it.
Now mount the EFS volume:
sudo mkdir /mnt/YOUR_MOUNT_POINT_DIR
sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 fs-YOUR_EFS_ID.efs.us-east-1.amazonaws.com:/ /mnt/YOUR_MOUNT_POINT_DIR
Now populate /mnt/YOUR_MOUNT_POINT_DIR with the 6 files mentioned in steps 1 and 2 using the following directory structure. Recall that you must create the passwd file the first time using the command 'vncpasswd'. It will create the file at ~/.vnc/passwd.
/mnt/YOUR_MOUNT_POINT_DIR/bin/installGui.sh /mnt/YOUR_MOUNT_POINT_DIR/bin/installXfce.sh
/mnt/YOUR_MOUNT_POINT_DIR/rsrc/vnc/vncservers-ec2-user /mnt/YOUR_MOUNT_POINT_DIR/rsrc/vnc/xstartup /mnt/YOUR_MOUNT_POINT_DIR/rsrc/vnc/passwd
/mnt/YOUR_MOUNT_POINT_DIR/rsrc/yum/yum.repos.d/centos.repo
At this point, setting up an instance with a GUI should be pretty easy. Create your instance as you normally would (make sure to include the MasterVNC security group), ssh to the instance, mount the EFS volume, and run the installGui.sh script.
You can take things a step further and launch your instance in 1 step using the AWS CLI tools on your local machine. To do this you will need to mount the EFS volume and run the installGui.sh script using arguments to the AWS CLI commands. This just requires creating a top level script and passing it to the CLI command.
Of course there are a couple complications. EC2 and EMR use different switches and mechanisms to attach the script. And furthermore, on EMR I only want the GUI to be installed on the master node (not the core or task nodes).
Launching an EC2 instance requires embedding the script in the command with the --user-data switch. This is done easily by specifying the absolute path to the script file on your local machine.
aws ec2 run-instances --user-data file:///PATH_TO_YOUR_SCRIPT/top.sh  ... other options
The EMR launch does not support embedding scripts from a local file. Instead you can specify an S3 URI in the bootstrap actions.
aws emr create-cluster --bootstrap-actions '[{"Path":"s3://YOUR_BUCKET/YOUR_DIR/top.sh","Name":"Custom action"}]' ... other options
Finally, you'll see in top.sh below most of the script is a function to determine if the machine is a basic EC2 instance or an EMR master. If not for that the script could be 3 lines. You may wonder why not just use the built in 'run-if' bootstrap action rather than writing my own function. The built in 'run-if' script has a bug and does not properly run scripts located in S3.
Debugging things once you put them in the init sequence can be a challenge. One thing that can help is the log file: /var/log/cloud-init-output.log. This captures all the console output from the scripts run during bootstrap initialization.
top.sh
#!/bin/bash
# note: conditional bootstrap function run-if has a bug, workaround ...
# this function adapted from https://forums.aws.amazon.com/thread.jspa?threadID=222418
# Determine if we are running on the master node.
# 0 - running on master, or non EMR node
# 1 - running on a task or core node
check_if_master_or_non_emr() {
    python - <<'__SCRIPT__'
import sys
import json
instance_file = "/mnt/var/lib/info/instance.json"
try:
    with open(instance_file) as f:
        props = json.load(f)
    is_master_or_non_emr = props.get('isMaster', False)
except IOError as ex:
    is_master_or_non_emr = True   # file will not exist when testing on a non-emr machine
if is_master_or_non_emr:
    sys.exit(1)
else:
    sys.exit(0)
__SCRIPT__
}
check_if_master_or_non_emr
IS_MASTER_OR_NON_EMR=$?
# If this machine is part of EMR cluster, then ONLY install on the MASTER node
if [ $IS_MASTER_OR_NON_EMR -eq 1 ]
then
    sudo mkdir /mnt/YOUR_MOUNT_POINT_DIR
    sudo mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 fs-YOUR_EFS_ID.efs.us-east-1.amazonaws.com:/ /mnt/YOUR_MOUNT_POINT_DIR
    . /mnt/YOUR_MOUNT_POINT_DIR/bin/installGui.sh
fi
exit 0
| 归档时间: | 
 | 
| 查看次数: | 7477 次 | 
| 最近记录: |