How to add an LXD container on another machine and copy Ansible's public keys to the container?

I am looking to use Ansible running on one machine to create a container on another machine and exchange ssh keys with it.

I am new to Ansible and have been trying different things based off a playbook I found on github:

`

---

- name: Ensure lxd is started
  service:
    name: lxd
    state: started

- name: Setup SSH for LXD
  blockinfile:
    marker: "# {mark} ANSIBLE BOOT LXD MANAGED BLOCK"
    dest: '{{ ssh_home }}/config'
    block: |
      Host *.lxd
          # No need for security for disposable test containers
          UserKnownHostsFile /dev/null
          StrictHostKeyChecking no
          User root

- name: Start lxd container
  lxd_container:
    name: '{{ item.split(".")[0] }}'
    state: started
    source:
      type: image
      mode: pull
      server: https://images.linuxcontainers.org
      protocol: lxd
      alias: '{{ hostvars[item].get("lxd_alias", "ubuntu/xenial/amd64") }}'
    profiles: ['default']
    wait_for_ipv4_addresses: true
  when: item.split('.')[-1] == 'lxd'
  with_items: '{{ groups["all"] }}'

- name: Add lxd host with lxd connection to setup python & ssh
  add_host:
    name: 'novafloss.boot-lxd-{{ item.split(".")[0] }}'
    ansible_ssh_host: '{{ item.split(".")[0] }}'
    ansible_connection: lxd
    group: 'novafloss.boot-lxd'
  when: item.endswith('.lxd')
  with_items: '{{ groups["all"] }}'

- name: Wait for containers to be connected
  shell: lxc exec {{ item.replace('.lxd', '') }} -- getent hosts google.com
  when: item.endswith('lxd')
  with_items: '{{ groups["all"] }}'
  retries: 30
  delay: 1

- name: Refresh packages
  raw: if hash apt-get; then apt-get update; elif hash apk; then apk update; fi
  become: no
  delegate_to: '{{ item }}'
  with_items: '{{ groups.get("novafloss.boot-lxd", []) }}'
  retries: 70

- name: Install sshd
  raw: if ! hash sshd; then if hash apt-get; then apt-get install -y openssh-server; elif hash apk; then apk add openssh; fi; fi
  become: no
  delegate_to: '{{ item }}'
  with_items: '{{ groups.get("novafloss.boot-lxd", []) }}'
  retries: 70

- name: Install python in container
  raw: if ! hash python2; then if hash apt-get; then apt-get install -y python; elif hash apk; then apk add python; fi; fi
  become: no
  delegate_to: '{{ item }}'
  with_items: '{{ groups.get("novafloss.boot-lxd", []) }}'
  retries: 70

- name: Gather facts
  setup:
  become: no
  delegate_to: '{{ item }}'
  with_items: '{{ groups.get("novafloss.boot-lxd", []) }}'
  register: setup

- name: Start and enable sshd
  service:
    name: sshd
    state: started
    enabled: yes
  become: no
  delegate_to: '{{ item }}'
  with_items: '{{ groups.get("novafloss.boot-lxd", []) }}'
  register: sshd
  ignore_errors: yes

- debug: var=item
  with_items: '{{ sshd.results }}'

- name: Start and enable OpenSSH (for when the above failed)
  service:
    name: ssh
    state: started
    enabled: yes
  become: no
  delegate_to: '{{ item["item"] }}'
  with_items: '{{ sshd.results }}'
  register: openssh
  when: "{{ item|failed }}"
  ignore_errors: yes
  failed_when: "item|failed and openssh|failed"

- name: Add your ssh key to the container
  authorized_key:
    key: '{{ lookup("file", ssh_public_key ) }}'
    path: /root/.ssh/authorized_keys
    user: root
  become: no
  delegate_to: '{{ item }}'
  with_items: '{{ groups.get("novafloss.boot-lxd", []) }}'

- name: Install sudo in container
  raw: if hash apt-get; then apt-get install -y sudo; elif hash apk; then apk add sudo; fi
  become: no
  delegate_to: '{{ item }}'
  with_items: '{{ groups.get("novafloss.boot-lxd", []) }}'
  retries: 70

- name: Wait for containers to start sshd
  wait_for:
    host: '{{ item }}'
    port: 22
    search_regex: OpenSSH
  when: item.endswith('lxd')
  with_items: '{{ groups["all"] }}'

`

One of the code variations I tried was:

`

- hosts: '{{ node }}'
  vars:
    node: 'machine'
    container_name: 'test123'
  tasks:
    - name: Start lxd container
      lxd_container:
        name: '{{ container_name }}'
        state: started
        source:
          type: image
          mode: pull
          server: https://images.linuxcontainers.org
          protocol: lxd
          alias: ubuntu/xenial/amd64
        profiles: ['default']
        wait_for_ipv4_addresses: true
        timeout: 600

    - name: Add lxd host with lxd connection to setup python & ssh
      add_host:
        name: '{{ container_name }}'
        ansible_ssh_host: '{{ container_name }}'
        ansible_connection: lxd
        group: 'lxd'

    - name: Install python in container
      raw: if ! hash python2; then if hash apt-get; then apt-get install -y python; elif hash apk; then apk add python; fi; fi
      become: no
      delegate_to: '{{ container_name }}'

    - name: Add your ssh key to the container
      authorized_key:
        key: '{{ lookup("file", "/root/.ssh/id_rsa.pub" ) }}'
        path: /root/.ssh/authorized_keys
        user: root
      become: no
      delegate_to: '{{ node }}'

`

I can successfully create the container however I have been struggling to add Ansible’s public key to the container.

How to can I add Ansible’s public key to a container which is running on another machine?

Hi,

Depending on the distro you run in the container you might be able to use cloud-init for it. This is what I do with ubuntu inside the container:

#Create a profile

  • name: create a bootstrap profile
    lxd_profile:
    name: bootstrap
    description: “used for bootstrapping of containers”
    state: present
    config: { “user.user-data”: “#cloud-config\nssh_authorized_keys:\n - ssh-rsa AAAAXXXXX== root@ponga\npackages:\n - openssh-server”}
    devices:
    eth0:
    name: eth0
    nictype: bridged
    parent: vlan2
    type: nic

And then I spin up the container using that profile:

  • name: create containers
    register: lxds
    lxd_container:
    name: “{{ item }}”
    state: started
    source:
    type: image
    properties:
    os: “ubuntu”
    release: “xenial”
    architecture: “amd64”
    profiles: [“bootstrap”]
    timeout: 600
    wait_for_ipv4_addresses: true
    with_items: “{{ hosts[inventory_hostname] }}”

Once I have the IP I added to local inventory:

  • name: update local inventory
    delegate_to: 127.0.0.1
    connection: local
    become: false
    copy: content=“[{{ item.item }}]\n{{ item.addresses.eth0[0] }} type=lxc” dest=“./inventory/dyn-{{ item.item }}”
    with_items: “{{ lxds.results }}”

  • meta: refresh_inventory

  • pause: seconds=60

This gives me a running container with running ssh (and an entry in the inventory).

kind regards
Pshem