This blog explains how to create a custom package in Debian OS. We will see how to configure a customize Debian package and create customize command.
Debian package creation in Ubuntu/Debian:
We will create the helloworld package without any command and with command like e.g.- ipaddr (to get external ip)
Create a debian package:
Let’s start creating empty directory helloworld. This folder will contain both source code and the Debian build instructions.
1.1 Create the debian/ Directory
Here we will use dh_make command to create the debian/ Directory:
$ mkdir -p Debian/helloworld-1.0 $ cd Debian/helloworld-1.01. Create debian/ folder with example files (.ex) $ dh_make \ –native \ –single \ –packagename helloworld_1.0.0 \ –email mukesh.waghadhare@talentica.com |
This created the debian/ folder. Explore them! Especially the example files (*.ex) as well as most importantly the files:
- debian/control
- debian/changelog
- debian/rules
1.2 Build the first (empty) Package
The dpkg-buildpackage command can be used to build first package:
$ dpkg-buildpackage -uc -us (-us, –unsigned-source Do not sign the source package (long option since dpkg 1.18.8). -uc, –unsigned-changes Do not sign the .changes file (long option since dpkg 1.18.8).) |
That’s it! This command build four files:
root@ip-172-31-19-221:/final_dpkg# ls -lrth
-rw-r–r– 1 root root 7.2K Jun 20 10:47 helloworld_1.0.0.tar.xz -rw-r–r– 1 root root 573 Jun 20 10:47 helloworld_1.0.0.dsc -rw-r–r– 1 root root 2.0K Jun 20 10:47 helloworld_1.0.0_amd64.deb -rw-r–r– 1 root root 4.7K Jun 20 10:47 helloworld_1.0.0_amd64.buildinfo -rw-r–r– 1 root root 1.5K Jun 20 10:47 helloworld_1.0.0_amd64.changes |
- .tar.gz: Source package, contains the contents of the helloworld/ folder
- .deb: Debian package, contains the installable package
- .dsc/.changes: Signature files, cryptographic signatures of all files
Let’s examine the contents with the dpkg -c command:
root@ip-172-31-19-221:/final_dpkg# dpkg -c helloworld_1.0.0_amd64.deb drwxr-xr-x root/root 0 2018-06-20 09:03 ./ drwxr-xr-x root/root 0 2018-06-20 09:03 ./usr/ drwxr-xr-x root/root 0 2018-06-20 09:03 ./usr/share/ drwxr-xr-x root/root 0 2018-06-20 09:03 ./usr/share/doc/ drwxr-xr-x root/root 0 2018-06-20 09:03 ./usr/share/doc/helloworld/ -rw-r–r– root/root 187 2018-06-20 09:03 ./usr/share/doc/helloworld/README.Debian -rw-r–r– root/root 144 2018-06-20 09:03 ./usr/share/doc/helloworld/changelog.gz -rw-r–r– root/root 1413 2018-06-20 09:03 ./usr/share/doc/helloworld/copyright root@ip-172-31-19-221:/final_dpkg# |
Nothing really in the package except the default changelog, copyright and README file.
1.3 Install the (empty) package
Let’s install it with dpkg -i command:
root@ip-172-31-19-221:/final_dpkg/helloworld-1.0# dpkg -i ../helloworld_1.0.0_amd64.deb (Reading database … 49055 files and directories currently installed.) Preparing to unpack ../helloworld_1.0.0_amd64.deb … Unpacking helloworld (1.0.0) over (1.0.0) … Setting up helloworld (1.0.0) … root@ip-172-31-19-221:/final_dpkg/helloworld-1.0# |
Done. That installed the package. Check out that it was actually installed by listing the installed packages with dpkg -l
# Proof that it’s actually installed
$ dpkg -l | grep helloworld ii helloworld 1.0.0 amd64 <insert up to 60 chars description> # ^^ ^ ^ ^ ^ # || | | | | # || | | | – Description # || | | – Architecture # || | – Version # || – Package name # | – Actual/current package state (n = not installed, i = installed, …) # – Desired package state (i = install, r = remove, p = purge, …) |
The columns in the list are desired package state, actual package state, package name, package version, package architecture and a short package description. If all is well, the first column will contain ii, which means that the package is properly installed.
Now that the package is installed, you can list its contents with the dpkg -L
root@ip-172-31-19-221:/final_dpkg# dpkg -L helloworld /. /usr /usr/share /usr/share/doc /usr/share/doc/helloworld /usr/share/doc/helloworld/README.Debian /usr/share/doc/helloworld/changelog.gz /usr/share/doc/helloworld/copyright root@ip-172-31-19-221:/final_dpkg# |
2.0 Adding files and updating the changelog
Let’s now add actual files in empty package. To do that, let’s create a folder file/usr/bin and add scripts to check IP address under ipaddr file.
$ mkdir -p files/usr/bin
$ touch files/usr/bin/ipaddr $ chmod +x files/usr/bin/ipaddr $ vi files/usr/bin/ipaddr # Script contents see below |
For this demo, we’ll use a short script to grab the public IP address from a service called ipify. It provides an API to return the IP address in various formats. We’ll grab it with curl in JSON and then use jq to parse out the ‘ip’ field:
#!/bin/bash
curl –silent ‘https://api.ipify.org?format=json’ | jq .ip –raw-output |
If we were to rebuild the package now, the dpkg-buildpackage command, we wouldn’t know which files to include in the package. So we’ll create the Debian/install file to list directories to include (e.g. vi Debian/install):
files/usr/* usr |
This basically means that everything in the files/usr/ folder will be installed at /usr/ on the target file system when the package is installed.
Once this is done, we can just rebuild and reinstall the package, but let’s go one step further and update the version of the package to 1.1.0. Versions are handled by the Debian/changelog file. You can update it manually, or use the dchscript (short for “Debian changelog”) to do so:
# We changed the package, let’s update the version and changelog for it to 1.0.3
$ dch -im # Opens the editor … root@ip-172-31-19-221:/final_dpkg/helloworld-1.0# cat debian/changelog helloworld (1.0.1) unstable; urgency=medium * Added ‘ipaddr’ script — root <mukesh.waghadhare@talentica.com> Thu, 21 Jun 2018 07:19:02 +0000 helloworld (1.0.0) unstable; urgency=medium * Initial Release. — root <mukesh.waghadhare@talentica.com> Wed, 20 Jun 2018 09:03:21 +0000 |
Let’s rebuild and reinstall the package:
root@ip-172-31-19-221:/final_dpkg/helloworld-1.0# dpkg-buildpackage -uc -us
(-us, –unsigned-source Do not sign the source package (long option since dpkg 1.18.8). -uc, –unsigned-changes Do not sign the .changes file (long option since dpkg 1.18.8).) |
Looks like it installed correctly. Let’s check if the ipaddr script is where it’s supposed to be. And then let’s try to run it:
root@ip-172-31-19-221:/final_dpkg/helloworld-1.0# dpkg -l | grep helloworld ii helloworld 1.0.1 amd64 <insert up to 60 chars description> root@ip-172-31-19-221:/final_dpkg/helloworld-1.0# which ipaddr /usr/bin/ipaddr root@ip-172-31-19-221:/final_dpkg/helloworld-1.0# ipaddr /usr/bin/ipaddr: line 2: jq: command not found (23) Failed writing body |
2.1 Updating description and adding dependencies
Each Debian package can depend on other packages. In the case of our ipaddr script, we use the curl and jqcommands, so the ‘helloworld’ package depends on these commands.
To add the dependencies to the ‘helloworld’ package, edit the Depends: section in the debian/control file (e.g. via vi debian/control):
root@ip-172-31-19-221:/final_dpkg/helloworld-1.0# vim debian/control Source: helloworld Section: utils Priority: optional Maintainer: mukeshw <mukesh.waghadhare@talentica.com> Build-Depends: debhelper (>= 9) Standards-Version: 3.9.8 Homepage: <insert the upstream URL, if relevant>Package: helloworld Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, curl, jq Description: Network management tools Includes various tools for network management. root@ip-172-31-19-221:/final_dpkg/helloworld-1.0# |
Again update the version and rebuild the package
Change the version:
root@ip-172-31-19-221:/final_dpkg/helloworld-1.0# dch -im root@ip-172-31-19-221:/final_dpkg/helloworld-1.0# cat debian/changelog * Updated description and depndancy — root <mukesh.waghadhare@talentica.com> Thu, 21 Jun 2018 07:19:48 +0000 helloworld (1.0.2) unstable; urgency=medium * Added ‘ipaddr’ script — root <mukesh.waghadhare@talentica.com> Thu, 21 Jun 2018 07:19:02 +0000 helloworld (1.0.0) unstable; urgency=medium * Initial Release. — root <mukesh.waghadhare@talentica.com> Wed, 20 Jun 2018 09:03:21 +0000 Rebuild: root@ip-172-31-19-221:/final_dpkg/helloworld-1.0# dpkg-buildpackage -uc -us Reinstall: root@ip-172-31-19-221:/final_dpkg/helloworld-1.0# dpkg -i ../helloworld_1.0.3_amd64.deb dpkg: error processing package helloworld (–install): |
unlike apt-get install, the dpkg -i command does not automatically resolve and install missing dependencies. It just highlights them. That is perfectly normal and expected. In fact, it gives us the perfect opportunity to check the package state (like we did above):
root@ip-172-31-19-221:/final_dpkg/helloworld-1.0# dpkg -l | grep helloworld iU helloworld 1.0.3 amd64 Network management tools# ^^ ^# || |# || – Yeyy, the new description# | – Actual package state is ‘U’ / ‘Unpacked’# – Desired package state is ‘i’ / ‘install’ |
As you can see by the output, the desired state for the package is ‘i’ (= installed), but the actual state is ‘U’ (= Unpacked). That’s not good. Luckily though, dependencies can be automatically resolved by apt-get install -f
root@ip-172-31-19-221:/final_dpkg/helloworld-1.0# apt-get install -f
Reading package lists… Done
Building dependency tree
Reading state information… Done
Correcting dependencies… Done
The following additional packages will be installed:
jq libjq1 libonig4
The following NEW packages will be installed:
jq libjq1 libonig4
0 upgraded, 3 newly installed, 0 to remove and 28 not upgraded.
1 not fully installed or removed.
Need to get 327 kB of archives.
After this operation, 1,157 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Processing triggers for man-db (2.7.6.1-2) …
Setting up jq (1.5+dfsg-1.3) …
Setting up helloworld (1.0.3) …
Finally, its installed correctly. Now, let’s test it…
root@ip-172-31-19-221:/final_dpkg/helloworld-1.0# dpkg -l | grep helloworld ii helloworld 1.0.3 amd64 Network management toolsroot@ip-172-31-19-221:/final_dpkg/helloworld-1.0# ipaddr 18.184.205.204 |
Conclusion:
This method makes it easy to install dependencies and multiple packages which we might require at bootup. It also installs a cluster of dependencies and customized packaged with the help of just one customized package.