Error's Enccountered While Installing Docker on Ubuntu 22.04 using Ansaible + Portainer
Here’s an error message you might encounter:
Failed to update apt cache: Updating from such a repository can’t be done securely and is therefore disabled by default. See apt-secure(8) manpage for repository creation and user configuration details., GPG error: https://download.docker.com/linux/ubuntu jammy InRelease: The following signatures couldn’t be verified because the public key is not available: NO_PUBKEY 7EA0A9C3F273FCD8, The repository ‘https://download.docker.com/linux/ubuntu jammy InRelease’ is not signed.
My intention was to install Docker and Python components to use Ansible to deploy docker-compose files on my Ubuntu host and then install Portainer. I started off with installing the docker playbook install_docker.yml
, then I ran install_portainer.yml
. The error I encountered was with install_docker.yml
, however, I would like to share a bit about the file type .yml.j2
and the Jinja2 templating engine.
With Jinja2, you can dynamically customize Docker Compose files based on variables that wouldn’t traditionally be defined within them. It offers an added layer of flexibility and customization. Think about scenarios where you need to deploy containers with varying configurations, ports, volumes, or service options. Jinja2 allows this variety without creating separate individual files for each. Instead, variables can be defined and altered at runtime or passed from Ansible playbooks, streamlining the creation and deployment of Docker environments dynamically.
Dynamically Templating docker-compose Files with .yml.j2 JINJA2 Templates
During Docker deployments, you may need containers with different environment configurations, ports, volumes, etc. Here, I’ll discuss how the file type .yml.j2
leverages the Jinja2 templating engine to simplify this process dynamically. You can dynamically customize your Docker Compose files rather than creating separate files for each different configuration.
A prime example of this is the setup of a Pi-hole server.
Here’s a typical docker-compose.yml.j2
file for a Pi-hole deployment:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
version: "3"
services:
pihole:
container_name: pihole
image: pihole/pihole:latest
ports:
- "53:53/tcp"
- "53:53/udp"
- "{{ http_port }}:80/tcp"
- "{{ https_port }}:443/tcp"
volumes:
- './etc-pihole/:/etc/pihole/'
- './etc-dnsmasq.d/:/etc/dnsmasq.d/'
environment:
ServerIP: "{{ server_ip }}"
TZ: "{{ timezone }}"
WEBPASSWORD: "{{ webpassword }}"
dns:
- 127.0.0.1
- 1.1.1.1
restart: unless-stopped
Here, we have templated the HTTP and HTTPS ports, server IP, timezone, and web password. Its flexibility allows it to cater to users who require different port numbers or differing environmental configurations (e.g., dev, test, prod).
The next part involves the section of the Ansible playbook, which will populate these templates with actual information:
1
2
3
4
5
6
7
8
9
10
- name: Create Docker Compose file from template
template:
src: docker-compose.yml.j2
dest: /path/to/docker-compose.yml
vars:
http_port: 80
https_port: 443
server_ip: "192.168.1.2"
timezone: "America/Toronto"
webpassword: "mypassword"
Ansible replaces the Jinja2 variables with the actual values specified in the vars section of the playbook, resulting in a properly configured docker-compose file ready for a Pi-hole deployment.
Addressing the error “The following signatures couldn’t be verified because the public key is not available: NO_PUBKEY 7EA0A9C3F273FCD8
Here are the sections of the original script I was using, which produced errors:
1
2
3
4
5
6
7
8
9
10
11
12
- name: Download Docker's official gpg key
get_url:
url: https://download.docker.com/linux/ubuntu/gpg
dest: /etc/apt/keyrings/docker.gpg
mode: 644
- name: Add Docker to the sources list
blockinfile:
path: /etc/apt/sources.list.d/docker.list
create: yes
block: |
deb [arch={{ dpkg_arch.stdout }} signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu {{ version_codename.stdout }} stable
This script consistently produced the error as stated above. After some research, I determined that the issue was with the line(s) specifying “/etc/apt/keyrings/docker.gpg”. So, I updated it from “gpg” to “asc”. This adjustment seemed to resolve the problem.
Here is the final script for deploying Docker with the required prerequisites for using Ansible to deploy docker-compose files on an Ubuntu host.
install_docker.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
- name: Set up Docker
hosts: newdocker
become: yes
tasks:
- name: Install prerequisites
apt:
name: "{{ item }}"
update_cache: yes
state: present
with_items:
- ca-certificates
- curl
- gnupg
- name: Download Docker's official GPG key
get_url:
url: https://download.docker.com/linux/ubuntu/gpg
dest: /etc/apt/keyrings/docker.asc
mode: 644
- name: Retrieve dpkg architecture
command: dpkg --print-architecture
register: dpkg_arch
- name: Retrieve version codename
shell: . /etc/os-release && echo "$VERSION_CODENAME"
register: version_codename
- name: Add Docker to sources list
blockinfile:
path: /etc/apt/sources.list.d/docker.list
create: yes
block: |
deb [arch={{ dpkg_arch.stdout }} signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu {{ version_codename.stdout }} stable
- name: Update apt-get
apt:
update_cache: yes
- name: Install Docker packages
apt:
name:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-buildx-plugin
- docker-compose-plugin
- python3-docker
- python3-pip
update_cache: yes
state: latest
- name: Install Docker Compose using pip
pip:
name: docker-compose
state: latest
Has anyone else had similar issues with GPG versus ASC in apt secure? Leave a comment below!
Installing Portainer
portainer-docker-compose.yml.j2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
version: "3.3"
services:
portainer:
image: portainer/portainer-ce:latest
restart: always
network_mode: bridge
ports:
- "8000:8000"
- "9000:9000"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "{{ host_dir }}:/data"
container_name: portainer
install_portainer.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- hosts: "*"
become: yes
vars:
container_name: portainer
host_dir: "/mnt/docker/portainer/{{ ansible_hostname }}"
docker_compose_dir: "/home/portainer/"
ansible_python_interpreter: /bin/python3
tasks:
- name: Create directory for nas storage
file:
path: "{{ host_dir }}"
state: directory
- name: Create directory for docker-compose
file:
path: "{{ docker_compose_dir }}/{{ container_name }}"
state: directory
- name: create a new docker-compose.yml file
template:
dest: "{{ docker_compose_dir }}/{{ container_name }}/docker-compose.yml"
src: "portainer-docker-compose.yml.j2"
- name: Run Portainer service using docker-compose
docker_compose:
project_src: "{{ docker_compose_dir }}/{{ container_name }}"
state: present
In wrapping up, I walked you through my process of using Ansible and Jinja2 for the installation of Docker and Portainer on an Ubuntu host. I showed you two uses on how Jinja2 can customize Docker Compose files, allowing for flexibility in deploying containers without duplication.
During the process, I encountered an error related to Docker’s official GPG key while using the install_docker.yml
playbook. The fix was to change “gpg” to “asc” in the respective lines of the playbook!
I hope you found this post insightful. Your feedback is most welcome.