Alpaquita Linux: Using Ansible to deploy Java applications
1. Ansible overview
Ansible is a popular automation tool for managing IT systems.
This document demonstrates several Ansible features for deploying a Spring Boot Java application on an Alpaquita Linux instance.
A control node is a system on which Ansible is installed.
Managed nodes are systems that Ansible controls.
Ansible initiates SSH connections from the control node to each managed node and executes necessary configuration operations on the managed node. These operations may include file modifications, starting or stopping services, adding users, and much more.
Configuration operations are written to YAML files called playbooks. Each playbook contains an ordered list of plays. Each play contains an ordered list of tasks. Each task lists one or more Ansible modules that define what operations should be performed.
Modules are grouped into collections, and Ansible ships with a large number of collections and modules to cover many scenarios.
In addition to regular tasks, Ansible also provides handlers, that is tasks, which are executed only when notified.
In comparison to scripting, Ansible is essentially a state engine, and all its tasks are idempotent, so playbooks are written with a declarative approach.
For example, you can see a playbook with two plays below. Each contains
only one task. The first one uses the
ansible.builtin.ping module to
ping systems in the
java_servers group. The second one uses the
ansible.builting.user module to declare that all systems in the same
group should have a user with the name
user and the comment
- name: First play hosts: java_servers tasks: - name: Ping ansible.builtin.ping: - name: Second play hosts: java_servers tasks: - name: Add a user ansible.builtin.user: name: user comment: A user
Ansible changes the configuration of the managed node only if the user does not exist or its parameters are different from those set in the playbook, that is when the actual state of the node differs from the declared state in the playbook.
Perform the following steps before you proceed to the next sections.
Set up 2 hosts: one is a control node and the other is a managed node.
Install Ansible on a control node that can be any UNIX-like system with Python 3.9 or newer installed.
On Fedora, you can install Ansible as follows:
sudo dnf install ansible
On Ubuntu, use the following command:
sudo apt-get install ansible
For other types of systems, refer to their documentation and the official Ansible installation guide.
For the other host, the managed node, we need an Alpaquita Linux instance. It can be any type of instances, such as bare-metal, virtual machine or an instance in a cloud as long as the following requirements are met:
A user with admin privileges is created;
An SSH access is set up from the control node to this instance using admin user credentials;
A Python interpreter is installed.
Visit the Alpaquita download page and choose the appropriate version of Alpaquita.
In our example the Alpaquita instance is a virtual machine deployed from
an iso. During installation, we assigned the
192.168.71.100 ip to
it. The user with admin privileges is
admin. A Python interpreter was
installed by connecting to the instance via SSH as
admin and executing
the following command:
sudo apk add python3
You will be creating some files during the course of this document. We
recommend keeping the files in one place. Create a separate directory on
the control node, for example:
alpaquita-ansible. All the next steps
are performed on the control node inside this directory.
3. Preparing an inventory
The number of managed nodes can be quite large, and specifying them all in the command line is cumbersome. Ansible provides an inventory file that contains logically organized sets of nodes.
Let’s create an inventory file named
inventory with the following
[alpaquita_nodes] alpaquita-node ansible_host=192.168.71.100 ansible_user=admin [alpaquita_nodes:vars] ansible_python_interpreter=/usr/bin/python3
In this file we declare a group of nodes named
contains a single node with the
alpaquita-node id with information
regarding its network address and the name of the user.
[alpaquita_nodes:vars] specifies variables for all members of
the corresponding group.
Substitute the address and username with your values.
Now, after we have created an inventory, we can verify that Ansible connects to our Alpaquita instance by pinging all nodes in the
ansible -i inventory -k -b -K -m ping alpaquita_nodes
-kinstructs Ansible to ask for an SSH password;
-boption tells Ansible that the user we are connecting as is not root, and in order to gain admin privileges it should use
sudoon the managed node, and the
-Koption makes Ansible ask for the sudo password.
4. Building a Java application
In this document we utilize the Spring PetClinic Sample Application Java application.
Build it on any machine with JDK Java 17 or later as follows:
git clone https://github.com/spring-projects/spring-petclinic.git cd spring-petclinic ./mvnw package
After the application is ready, save the generated
spring-petclinic.jar in the
alpaquita-ansible directory on the
5. Installing Java
To make Java applications work on our Alpaquita instance, install a JRE.
Alpaquita repositories provide
Liberica JRE, so in order to install
it create a playbook file named
playbook.yaml with a single task.
- name: Alpaquita setup hosts: alpaquita_nodes tasks: - name: Install Liberica JRE community.general.apk: name: liberica17-lite-jre-no-deps
In Alpaquita, packages are managed by
so you can use the
community.general.apk Ansible module for package
Execute the playbook
playbook.yaml with the following command:
ansible-playbook -b -k -K -i inventory playbook.yaml
This command is the common command that we will use to execute the playbook later in this document.
6. Creating an application user
PetClinic is a web application. Running web applications under a user
with admin privileges can lead to security issues, therefore we will
create a special user and substitute our existing
admin user with the
newly created one.
Add the following tasks to
playbook.yaml to create a new user:
- name: Install shadow package community.general.apk: name: shadow - name: Add petclinic group ansible.builtin.group: name: petclinic - name: Add petclinic user ansible.builtin.user: name: petclinic group: petclinic comment: PetClinic home: /home/petclinic create_home: true shell: /sbin/nologin password: !
We install the
shadow package, because it provides
useradd utilities that are not present in the default Alpaquita
Setting the shell to
/sbin/nologin and password to
interactive login as the
Apply the configuration by executing the playbook. The
and group should be created in the system.
7. Deploying a Spring Boot application
Add the following task to the playbook to copy the application’s jar to the Alpaquita system:
- name: Copy jar ansible.builtin.copy: src: spring-petclinic.jar dest: /home/petclinic owner: petclinic group: petclinic mode: 0444
After that execute the playbook.
Now we can manually start the application. Login to the Alpaquita system
admin user and execute the following command:
sudo -u petclinic java -jar /home/petclinic/spring-petclinic.jar
Now open the http://192.168.71.100:8080 URL in a web browser to see that the application is actually running.
spring-petclinic.jar application before proceeding to the
8. Converting the application into a service
Starting applications as described in the previous section can be useful sometimes, but you can automate such routine operations. Convert the manual startup operations into a service and let a service manager be responsible for starting and stopping our applications when needed.
Alpaquita uses OpenRC to manage services. Services are defined in shell script files.
In this case, we create a definition of a new service in
#!/usr/sbin/openrc-run name="PetClinic service" command="/usr/bin/java" command_args="-jar /home/petclinic/spring-petclinic.jar" command_background=true pidfile="/run/$RC_SVCNAME.pid" command_user="petclinic:petclinic"
Update the playbook and add tasks for copying the service file to the correct location and ensuring that the new service is running and automatically starts on system boot.
- name: Copy the service file ansible.builtin.copy: src: spring-petclinic-service.sh dest: /etc/init.d/petclinic owner: root group: root mode: 0755 - name: Enable petclinic service ansible.builtin.service: name: petclinic enabled: true state: started
After executing the playbook, open http://192.168.71.100:8080 in a browser to see that the application is running. If you reboot the Alpaquita instance, the application starts automatically.
9. Handling application updates
If you update
spring-petclinic.jar with a new version and execute the
Copy jar task updates the configuration of the system by
copying a new version of the file. However, the
petclinic service is
not restarted and runs the previous version of the application.
To update the
.jar file, we introduce a new handler to restart the service and make the
Copy jar task notify this handler after it has updated system configuration.
The updated playbook should look like the following (with irrelevant parts omitted):
- name: Alpaquita setup hosts: alpaquita_nodes tasks: <...> - name: Copy jar ansible.builtin.copy: src: spring-petclinic.jar dest: /home/petclinic <...> notify: - Restart petclinic service <...> handlers: - name: Restart petclinic service ansible.builtin.service: name: petclinic state: restarted
To verify the update procedure, go to the directory with PetClinic sources, update the image of pets displayed on the application welcome page with a new picture, and build a new jar file.
curl https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png \ -o ./src/main/resources/static/resources/images/pets.png git add src/main/resources/static/resources/images/pets.png git commit -m 'Updated pets.png' rm -rf target ./mvnw package
Copy the generated jar file to
spring-petclinic.jar and execute the
playbook. Ansible notifies that it is copying the new file and
restarting the service. Refreshing the page in the browser also shows
the new image (depending on your browser, it may be necessary to perform
the "force refresh" of the page).
This document only briefly describes a few Ansible features, but it can help you set up a system for some simple use cases.
If there is a requirement to have a system with an identical
configuration, all you need to do is set up a new system and add a new
line with access information to
You can go further and also perform provisioning of new systems with Ansible. For example, the Ansible ships AWS, Azure and, GCP modules to work with cloud resources, therefore you can make Ansible create your virtual machines in the cloud and configure them the way you need.
For more information, refer to the official Ansible documentation.