Set up Artifactory with Ansible

Hello weekend!

What do I have today, simple as last post, set up Arifactory via Ansible. Simple enough, right! Yeah, with some enhanced requirements


Use Case:

Create a new VM from KVM, do all the set up to connect to this VM via Ansible then set up Artifactory, do the configuration wizard and join this VM to domain. Sound simple, right!


Solution:

Alright, it's straight forward on what we have to do so there is no analysis for the implementation. First thing is you have to install qemu, libvirt, virt manager ... for KVM, let talk about this in other post. I also got a great help from my boss that he helps me to create a script for create new vm then install Ubuntu into it (let's talk about libvirt and KVM later), here are some simple command from virsh

virt-install                           \
        --connect qemu:///system       \
        --virt-type kvm                \
        --os-type linux                \
        --os-variant $os_variant       \
        --name $name                   \
        --ram $ram_mb                  \
        --disk path=$image_file,format=qcow2,size=$disk_gb \
        --vcpus $vcpus                 \
        --graphics none                \
        --network default              \
        --noautoconsole                \
        --location $location           \
        --initrd-inject $config_path   \
        --extra-args "$extra_args"     \
        --noreboot

virsh list -a : list all kvm
virsh start --domain [vmname] : start a vm/domain
virsh restart --domain [vmname]
virsh shutdown --domain

virsh snapshot-list --domain [vmname]
virsh snapshot-create-as --domain [vmname] --name [snapshotname] --description [description]
virsh snapshot-revert --domain [vmname] --snapshotname [snapshotname] --running
virsh snapshot-delete --domain [vmname] --snapshotname [snapshotname]

So, after you create a new vm, make sure this vm has a common user for ansible connection via ssh. So the next task is how you get the IP of this vm because this newly born vm can't be identify by any other ID without joining dns to have a hostname registered. So a manual way is open that vm (via VNC) and use ifconfig. Then I tried with this discussions where we will send an nmap ping package to all machines on network in order to register the new VM into the Address Resolution on our machine

nmap -sP -n [netmask] (something like 192.168.0.0/24)

Then get the IP via script at first, I try to use

virsh net-dhcp-leases [interface] (default or br0)

but then after my IT change the bridge interface then this call doesn't response anything. I use this script

vmname=$1
mac=$(virsh domiflist $vmname | grep br0 | awk '{print $NF}')
ip=$(arp -n | grep $mac | awk '{print $1}')
echo $ip

But there is problem, again, if the host machine hasn't ping or reach out to this vm then the host doesn't have a record of this vm ip mapping in its ARP cache. So, I have to leave this automatic step aside, maybe fping in the discussion might worth a try (or arp-scan, some play around with cleaning up the arp cache here)

So the next step is setting up the vm that can be connected via ansible. Fortunately, during the OS installation, I got python 2.7 installed and a user added as sudoer (let call 'ansible'). Now I have to copy the key pair of 'ansible' user to the new vm. How to let my host recognize the new vm, adding the vm rsa hashcode to the known_hosts of the host machine by

ssh-keyscan -t rsa [vmip] >> /etc/ansible/.ssh/known_hosts

Then copy the public key to remote vm (in order to create the .ssh directory under ansible home) then you can copy the whole .ssh directory of ansible user from host machine to remote machine. Because when you copy the ssh public key for the first time with ssh-copy-id, it will ask you to enter the password so there is a solution is sshpass tool.

sshpass -f [passfile] ssh-copy-id ansible@[vmip]
scp -r -i [path/to/local/privatekey] /home/ansible/.ssh ansible@[vmip]:/home/ansible

Voila, you have the key pair of ansible user to be in the remote machine, your ansible script is ready.

This time, a bit enhancement from last time. I will apply the ansible role which is recommended via its best practices. So my directory structure is like this

ansible
     |_ artifactory_pb.yml
     |_ servers
     |_ credentials.yml              # sudo password encrypted by vault
     |_ .vault_pwd                     # vault password to decrypt
     |_ roles
            |_ artifactory
                       |_ vars             # variables for artifactory installation
                       |_ tasks           # tasks for artifactory installation
                       |_ templates    # template files for artifactory installation
            |_ server
                    |_ vars                # variables for server installation
                    |_ tasks              # tasks for server installation
                    |_ templates       # templates for server installation
                    |_ files                # files for server installation

Some notes that I haven't found in official guide or just put them together
  • In the main playbook, you can use the roles as below (this is from ansible docs)
---
- hosts: [artifactory]
  vars_files:
   - credentials.yml
  roles:
   - artifactory
   - server
  • In the role task yml, you don't have to include hosts ... just start from the tasks: then the task list will be executed.
  • Make sure you have the directory structure and the main.yml naming like that


To install artifactory, just follow their official guide. It's quite simple with a note that you have to have apt-transport-https in order to have your fresh vm to connect via https. I have another request is to change the access port to default 80 instead of 8081 from artifactory, there is a way to do this by setting up revert proxy on your artifactory so it will do the port forwarding from 80 in the outside call to 8081 into embed tomcat of artifactory. Then, you have to install nginx and do the configuration for nginx web server in /etc/nginx/conf.d/nginx.conf.

With the configuration script in the guideline, you will use it as the nginx.conf, you need to change the server name in this config file so you should use this nginx.conf as a template with j2 extention (template vs copy in ansible is that template with use jinja to replace the variables within the template file content). After copy the nginx.conf you have to restart nginx service.

In order to complete the setup wizard, you have to enter the artifactory license (register for a license then it will send you a license file), change the admin password then activate a repository. Artifactory has a huge guideline to show you how to start artifactory via an import yml file. This yml file is created by default in $ARTIFACTORY_HOME/misc/artifactory.config.template.yml, then you copy it to $ARTIFACTORY_HOME/etc/artifactory.config.import.yml and update with your configuration. Note: by default $ARTIFACTORY_HOME is /var/opt/jfrog/artifactory.

For my case, I will change the licenseKey and uncomment which repository that I want to create (use fileinline module to make change on remote file). After this step, you are done by starting the artifactory service. You can refer to this project for more information.

So this should be done for the artifactory setup and configuration. My next step is joining this machine into domain to have the filesystem setting from the domain configuration (unfortunately, I have no idea how the IT has done it, just some magics ... :D ). We will edit the nsswitch.conf, idmapd.conf to point to the dns and login information, add the defaultdomain for the nis installation. There are some notes for these steps as below, I don't know how but there is a bug with rpcbind.service so my new machine can't auto start this service until you add it with:

systemctl add-wants multi-user.target rpcbind.service
systemctl start rpcbind.service

When reboot server with ansible, you might find a lot of sample there but there is a small tweak to avoid the error in your playbook

  - name: reboot
    shell: sleep 2 && /sbin/reboot
    async: 1
    poll: 0

  - name: wait for rebooting
    local_action: wait_for host={{ ansible_host }} delay=20 port=22 state=started

Unfortunately, after I joined my machine to the domain, there is a policy (not sure what policy, maybe with the fuse.conf) that doesn't allow the root user read/access the [user]/.ansible/tmp so my playbook will fail when I use become/sudo to root. So I apply from this fix to change the ansible.cfg in ansible directory

remote_tmp     = /tmp/${USER}/.ansible 
instead of # ~/.ansible/tmp

So my new machine has worked now, it should be some more improvement but you can be good for a starting point!

Happy reading!

Comments