Getting a Basic Cobbler server going on CentOS.


I love Cobbler.

Cobbler + Chef in my environment means that I can go from bare metal to an active cluster node in moments with little effort.

It is a powerful system for managing kickstart profiles, pxeboot, power, dhcp, dns etc..

Below are some notes to help get you going with just the basic feature set. It is a system you can easy go nuts with to automate a lot of your infrastructure.

Install it from EPEL.

yum -y install cobbler cobbler-web xinetd tftp

Fix Authentication For The Web Interface.

sed -i 's/authn_denyall/authn_configfile/g' /etc/cobbler/modules.conf

Change the password for the ‘Cobbler’ administative user.

htdigest /etc/cobbler/users.digest "Cobbler" cobbler

Set the Server Name.

sed -i 's/server: 127.0.0.1/server: cobbler.example.com/g' /etc/cobbler/settings

Set kickstarted nodes to turn off pxeboot on sucessful install.

sed -i 's/pxe_just_once: 0/pxe_just_once: 1/g' /etc/cobbler/settings

Setup Anamon to log installs to /var/log/cobbler/anamon/<hostname> on the cobbler server.

sed -i 's/anamon_enabled: 0/anamon_enabled: 1/g' /etc/cobbler/settings

Although we’re not running dhcpd on this server but I find it answers well to fill this out regardless.

sed -i 's/next_server: 127.0.0.1/next_server: 192.168.1.1/g' /etc/cobbler/settings

Fire cobblerd up.

/etc/init.d/cobblerd start

Swap out the cobbler_web.conf with one that will attach to a cname.

mv /etc/httpd/conf.d/cobbler_web.{conf,dist}
cat <<EOF > /etc/httpd/conf.d/cobbler_web.conf
<VirtualHost *:80>
ServerName cobbler.example.com
ServerAlias cobbler
SetEnvIf Request_URI ".*/op/events/user/.*" dontlog
CustomLog logs/access_log combined env=!dontlog
<Location "/cobbler_web">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE settings
# PythonOption django.root /cobbler_web
PythonDebug On
PythonPath "['/usr/share/cobbler/web/'] + sys.path"
AuthBasicAuthoritative Off
AuthType basic
AuthName "Cobbler"
Require valid-user
PythonAuthenHandler cobbler_web.views
</Location>
</VirtualHost>
EOF

Restart httpd.

/etc/init.d/httpd restart

To get tftpd going edit /etc/xinetd.d/tftp

set disable = no

Restart xinetd.

/etc/init.d/xinetd restart

Houskeeping items to pass the cobbler check (I’m not running debian).

cobbler get-loaders
sed -i -e 's|@dists=.*|#@dists=|'  /etc/debmirror.conf
sed -i -e 's|@arches=.*|#@arches=|'  /etc/debmirror.conf

On your DHCP server make sure it is pointed at the cobbler server.

next-server IP.OF.COBBER.SERVER;
filename "/pxelinux.0";

Make it auto start.

chkconfig cobblerd on
chkconfig xinetd on
chkconfig httpd on

Sync the cobbler config.

cobbler sync

And we’re good to go, now you can get to the cobbler server at http://cobbler.example.com/cobbler_web/

From here we can work in the web interface as well as through the CLI.

Lets first setup a Distro.

I run cobbler on the same node as I host my local CentOS Mirror (see this article) so to setup a distro I just need to tell Cobbler where to find the vmlinuz and initrd.img files.

cobbler distro add \
  --arch=x86_64  \
  --breed=redhat \
  --os-version=rhel6 \
  --name=CentOS6 \
  --initrd=/path/to/repo/CentOS/6/os/x86_64/isolinux/initrd.img \
  --kernel=/path/to/repo/CentOS/6/os/x86_64/isolinux/vmlinuz

And here is what it looks like in the web interface.

Now add your local repos that we built in the previous article.

cobbler repo add \
  --arch=x86_64 \
  --breed=yum \
  --keep-updated=N \
  --mirror=http://repo.example.com/CentOS/6/os/x86_64/ \
  --name=CentOS6-Base 

cobbler repo add \
  --arch=x86_64 \
  --breed=yum \
  --keep-updated=N \
  --mirror=http://repo.example.com/CentOS/6/updates/x86_64/ \
  --name=CentOS6-Updates 

Once again, the web interface.

Now lets start building our kickstart templates. First, lets make some snippets that will be compiled into the main kickstart file.

Place the pre-run trigger snippet here: /var/lib/cobbler/snippets/kickstart_start

#set system_name = $getVar('system_name','')
#set profile_name = $getVar('profile_name','')
#set breed = $getVar('breed','')
#set srv = $getVar('http_server','')
#set run_install_triggers = $str($getVar('run_install_triggers',''))
#set runpre = ""
#if $system_name != ''
    ## RUN PRE TRIGGER
    #if $run_install_triggers in [ "1", "true", "yes", "y" ]
        #if $breed == 'redhat'
            #set runpre = "\nwget "http://%s/cblr/svc/op/trig/mode/pre/%s/%s" -O /dev/null" % (srv, "system", system_name)
        #else if $breed == 'vmware'
            #set runpre = "\nwget "http://%s/cblr/svc/op/trig/mode/pre/%s/%s" -O /dev/null" % (srv, "system", system_name)
        #end if
    #end if
#else if $profile_name != ''
    ## RUN PRE TRIGGER
    #if $run_install_triggers in [ "1", "true", "yes", "y" ]
        #if $breed == 'redhat'
            #set runpre = "\nwget "http://%s/cblr/svc/op/trig/mode/pre/%s/%s" -O /dev/null" % (srv, "profile", profile_name)
        #else if $breed == 'vmware'
            #set runpre = "\nwget "http://%s/cblr/svc/op/trig/mode/pre/%s/%s" -O /dev/null" % (srv, "profile", profile_name)
        #end if
    #end if
#end if
#echo $runpre

And the post triggers snippet here: /var/lib/cobbler/snippets/kickstart_done

#set system_name = $getVar('system_name','')
#set profile_name = $getVar('profile_name','')
#set breed = $getVar('breed','')
#set os_version = $getVar('os_version','')
#set srv = $getVar('http_server','')
#set kickstart = $getVar('kickstart','')
#set run_install_triggers = $str($getVar('run_install_triggers',''))
#set pxe_just_once = $str($getVar('pxe_just_once',''))
#set nopxe = ""
#set saveks = ""
#set runpost = ""
#if $system_name != ''
    ## PXE JUST ONCE
    #if $pxe_just_once in [ "1", "true", "yes", "y" ]
        #if $breed == 'redhat'
            #set nopxe = "\nwget "http://%s/cblr/svc/op/nopxe/system/%s" -O /dev/null" % (srv, system_name)
        #else if $breed == 'vmware' and $os_version == 'esx4'
            #set nopxe = "\ncurl "http://%s/cblr/svc/op/nopxe/system/%s" -o /dev/null" % (srv, system_name)
        #else if $breed == 'vmware' and $os_version == 'esxi4'
            #set nopxe = "\nwget "http://%s/cblr/svc/op/nopxe/system/%s" -O /dev/null" % (srv, system_name)
        #end if
    #end if
    ## SAVE KICKSTART
    #if $kickstart != ''
        #if $breed == 'redhat'
            #set saveks = "\nwget "http://%s/cblr/svc/op/ks/%s/%s" -O /root/cobbler.ks" % (srv, "system", system_name)
        #else if $breed == 'vmware' and $os_version == 'esx4'
            #set saveks = "\ncurl "http://%s/cblr/svc/op/ks/%s/%s" -o /root/cobbler.ks" % (srv, "system", system_name)
        #else if $breed == 'vmware' and $os_version == 'esxi4'
            #set saveks = "\nwget "http://%s/cblr/svc/op/ks/%s/%s" -O /var/log/cobbler.ks" % (srv, "system", system_name)
        #end if
    #end if
    ## RUN POST TRIGGER
    #if $run_install_triggers in [ "1", "true", "yes", "y" ]
        #if $breed == 'redhat'
            #set runpost = "\nwget "http://%s/cblr/svc/op/trig/mode/post/%s/%s" -O /dev/null" % (srv, "system", system_name)
        #else if $breed == 'vmware' and $os_version == 'esx4'
            #set runpost = "\ncurl "http://%s/cblr/svc/op/trig/mode/post/%s/%s" -o /dev/null" % (srv, "system", system_name)
        #else if $breed == 'vmware' and $os_version == 'esxi4'
            #set runpost = "\nwget "http://%s/cblr/svc/op/trig/mode/post/%s/%s" -O /dev/null" % (srv, "system", system_name)
        #end if
    #end if
#else if $profile_name != ''
    ## SAVE KICKSTART
    #if $kickstart != ''
        #if $breed == 'redhat'
            #set saveks = "\nwget "http://%s/cblr/svc/op/ks/%s/%s" -O /root/cobbler.ks" % (srv, "profile", profile_name)
        #else if $breed == 'vmware' and $os_version == 'esx4'
            #set saveks = "\ncurl "http://%s/cblr/svc/op/ks/%s/%s" -o /root/cobbler.ks" % (srv, "profile", profile_name)
        #else if $breed == 'vmware' and $os_version == 'esxi4'
            #set saveks = "\nwget "http://%s/cblr/svc/op/ks/%s/%s" -O /var/log/cobbler.ks" % (srv, "profile", profile_name)
        #end if
    #end if
    ## RUN POST TRIGGER
    #if $run_install_triggers in [ "1", "true", "yes", "y" ]
        #if $breed == 'redhat'
            #set runpost = "\nwget "http://%s/cblr/svc/op/trig/mode/post/%s/%s" -O /dev/null" % (srv, "profile", profile_name)
        #else if $breed == 'vmware' and $os_version == 'esx4'
            #set runpost = "\ncurl "http://%s/cblr/svc/op/trig/mode/post/%s/%s" -o /dev/null" % (srv, "profile", profile_name)
        #else if $breed == 'vmware' and $os_version == 'esxi4'
            #set runpost = "\nwget "http://%s/cblr/svc/op/trig/mode/post/%s/%s" -O /dev/null" % (srv, "profile", profile_name)
        #end if
    #end if
#end if
#echo $saveks
#echo $runpost
#echo $nopxe

I also use cobbler to bootstrap chef. Drop it at /var/lib/cobbler/snippets/chef-bootstrap

# Chef Needs the clock to be synced.
cat <<EOF_NTP >> /etc/ntp/step-tickers
0.centos.pool.ntp.org
1.centos.pool.ntp.org
2.centos.pool.ntp.org
EOF_NTP

chkconfig ntpd on
service ntpd start

# MyRepo has the Opscode Chef full-stack installer RPM.
cat <<EOF_REPO >> /etc/yum.repos.d/MyRepo.repo
[MyRepos]
name=MyRepo
baseurl=http://repo.example.com/MyRepo/el/6/x86_64/
enabled=1
keepcache=0
gpgcheck=0
EOF_REPO

yum -y install gcc chef-full
# Installs some Gems I need.
/opt/opscode/embedded/bin/gem install mongrel --pre
/opt/opscode/embedded/bin/gem install ruby-shadow
mkdir /etc/chef
cd /etc/chef
curl -O http://chef.example.com/validation.pem
curl -O http://chef.example.com/client.rb
# Run chef-client to register the node
chef-client
chkconfig --add chef-client
chkconfig chef-client on
service chef-client start

# Run chef-client again setting up the node in our Base Profile.
cat <<EOF > /var/tmp/role.json
{ "run_list": [ "role[Base]" ] }
EOF
chef-client -j /var/tmp/role.json

Disk setup here. In a system’s profile you can pass disks=single or disks=mirror to pick a disk layout. I have different disk configs for MySQL servers, Hadoop nodes, web servers etc..

/var/lib/cobbler/snippets/disk-setup

clearpart --all --initlabel

#if $disks == 'mirror'
bootloader --location=mbr --driveorder=sda,sdb
part raid.01 --size=300 --asprimary --ondisk=sda
part raid.11 --size=300 --asprimary --ondisk=sdb
part raid.02 --size=1 --grow --asprimary --ondisk=sda
part raid.12 --size=1 --grow --asprimary --ondisk=sdb
raid /boot --fstype=ext3 --device md0 --level=RAID1 raid.01 raid.11
raid pv.01 --fstype ext3 --device md1 --level=RAID1 raid.02 raid.12  
volgroup centos pv.01
logvol /         --fstype ext3 --name=root     --vgname=centos --size=10240
logvol /var      --fstype ext3 --name=var      --vgname=centos --size=10240
logvol /home     --fstype ext3 --name=home     --vgname=centos --size=5120
logvol /opt      --fstype ext3 --name=opt      --vgname=centos --size=5120
logvol swap      --fstype swap --name=swap     --vgname=centos --size=4096

#else

#if $disks == 'single'
bootloader --location=mbr --driveorder=sda
part /boot --fstype ext3 --size=300 --asprimary --ondisk=sda
part pv.01   --size=150 --grow --ondisk=sda
volgroup centos pv.01
logvol /         --fstype ext3 --name=root     --vgname=centos --size=10240
logvol /var      --fstype ext3 --name=var      --vgname=centos --size=10240
logvol /home     --fstype ext3 --name=home     --vgname=centos --size=5120
logvol /opt      --fstype ext3 --name=opt      --vgname=centos --size=5120
logvol swap      --fstype swap --name=swap     --vgname=centos --size=4096

#end if
#end if

I also seperate packages, since eventually I’ll setup an if/else tree for different node types.

/var/lib/cobbler/snippets/packages

@editors
@core
@base
device-mapper-multipath
-sysreport
-sendmail
-logwatch
screen
ntp
net-snmp
net-snmp-utils
system-config-date
system-switch-mail
postfix
nfs-utils
sysstat
yum-priorities

And finally, drop your kickstart with integrated snippets (you can generate a rootpw crypt thus: openssl passwd -1).

/var/lib/cobbler/kickstarts/myCentOS6.ks

authconfig --enableshadow --enablemd5
rootpw --iscrypted $1$NDnhVSEW$YeKmfHm.Fi7rRKhjpO2bF1
text
skipx
keyboard us
lang en_US.UTF-8
timezone  America/New_York
firewall --disabled
selinux --disabled
url --url=$tree
$yum_repo_stanza
$SNIPPET('network_config')
firstboot --disable
reboot
$SNIPPET('disk-setup')
install
%pre
$SNIPPET('log_ks_pre')
$kickstart_start
$SNIPPET('pre_install_network_config')
$SNIPPET('pre_anamon')
%packages
$SNIPPET('packages')
%post
$SNIPPET('log_ks_post')
$yum_config_stanza
$SNIPPET('post_install_kernel_options')
$SNIPPET('post_install_network_config')
$SNIPPET('func_register_if_enabled')
$SNIPPET('download_config_files')
$SNIPPET('koan_environment')
$SNIPPET('redhat_register')
$SNIPPET('cobbler_register')
$SNIPPET('chef-bootstrap')
yum -y upgrade
$SNIPPET('post_anamon')
$SNIPPET('kickstart_done')

Most of those snippets come with Cobbler already.

And now, lets make a profile.

cobbler profile add \
  --kickstart=/var/lib/cobbler/kickstarts/myCentOS6.ks \
  --repos="CentOS6-Base CentOS6-Updates" \
  --nameservers="192.168.1.1 192.168.1.2"
  --distro=CentOS6 \
  --name=CentOS6-x86_64

And, again with the web interface….

Sync it all with Cobbler.

cobbler sync

And now we have all the pieces in place to add a node with a RAID1 mirror that will netboot on next boot.

cobbler system add \
  --name=server01.example.com \
  --profile=CentOS6-x86_64 \
  --mac=1a:2b:3c:4d:5e:6f \
  --ip=192.168.1.3 \
  --subnet=255.255.255.0 \
  --hostname=server01.example.com \
  --ksmeta="disks=mirror" \
  --netboot-enabled=Y \
  --gateway=192.168.1.1

Here is the node in the web interface.

There you have it. Enable PXE booting on the node and reboot it.

You can actually follow it’s install process from the Cobbler server

tail -f /var/log/cobbler/anamon/server01.example.com/*

Within a few minutes your node will be complete.

Share
  • http://blog.mindlesstechie.net/ John Alberts

    Thank you very much for writing this as well as your other articles.  It’s nice to have something to follow to just get something up and running quickly and then invest the time to actually learn how to use the tool.

  • Bob Cochran

    Suppose this is for a home network that utilizes Verizon’s FIOS. Setting up a cobbler server means I also need to have a named (dns) server running and probably a dhcp server is a good idea too. 

  • Vincent Swart

    Brilliant instructions, Nathan! I’d like to follow your posts using an RSS feed but I can’t find a link for it.

  • Paul Anthony Mcgowan

    Excellent post, I get error though : Syntax error on line 8 of /etc/httpd/conf.d/cobbler_web.conf:
    Invalid command ‘PythonHandler’, perhaps misspelled or defined by a module not included in the server configuration

    I tried both the cobbler 2.2.3 from the repo and also version 2.2.1 which I built from source rpm and I know works fine.

    Tips from anyone welcome ! Thanks

    • Lukas Grimm

       install mod_python to solve that

      • Paul Anthony Mcgowan

        Thanks.

  • Stuart J Sears

    Thanks for this. Any objection to me linking (or stealing bits of this) for the cobbler wiki chef section?

    • http://blog.milford.io Nathan Milford

      Sure.

      I have a large backlog of blog posts to write (I haven’t updated since March), and at least three of them are cobbler related (replication, triggers and xml-rpc).  When I post them you are free to borrow.

      - n

      • Stuart Sears

        Thanks, I’ll link back to this article.
        You’re also welcome to add them to the wiki for cobbler, if you’d like to share them… the more info the better, quite frankly.

        https://github.com/cobbler/cobbler/wiki

        Stuart

        • http://blog.milford.io Nathan Milford

          Roger that.  when I get around to moving this site to Octopress I’ll work on it.

          We’re also working on using Razer – http://puppetlabs.com/solutions/next-generation-provisioning/ – to boot, and setup nodes in Cobbler (grab mac addrs) so we can provision without manual intervention.

          There will be more on that :)