Boot config to deploy containers
This defines environment files which declare a resource type Heat::InstallConfigAgent. This can be used by server user_data when booting a pristine image to install parts to deploy a container with docker-compose or atomic hook. This container would then help deploy all other 'docker-compose' and 'atomic' SoftwareConfig resources. Example template can be run with downloadable Fedora Atomic Host image or RHEL Atomic Host, specifically tailored for use with containers. https://getfedora.org/cloud/download Change-Id: Ib5bdcef1111ec9a0bcf588ece277b9328f6e6def
This commit is contained in:
parent
eb3b82b7d1
commit
24e45841cb
@ -30,3 +30,26 @@ When creating the stack, reference the desired environment, eg:
|
||||
heat stack-create -e fedora_yum_env.yaml \
|
||||
-f ../example-templates/example-config-pristine-image.yaml \
|
||||
deploy-to-pristine
|
||||
|
||||
=====================================
|
||||
Boot config with heat-container-agent
|
||||
=====================================
|
||||
|
||||
When creating the stack to deploy containers with docker-compose,
|
||||
include the following in the template:
|
||||
|
||||
boot_config:
|
||||
type: Heat::InstallConfigAgent
|
||||
|
||||
server:
|
||||
type: OS::Nova::Server
|
||||
properties:
|
||||
user_data_format: SOFTWARE_CONFIG
|
||||
user_data: {get_attr: [boot_config, config]}
|
||||
# ...
|
||||
|
||||
and refrence the desired environment, eg:
|
||||
|
||||
heat stack-create -e container_agent_env.yaml \
|
||||
-f ../example-templates/example-pristine-atomic-docker-compose.yaml \
|
||||
deploy-to-pristine
|
||||
|
4
hot/software-config/boot-config/container_agent_env.yaml
Normal file
4
hot/software-config/boot-config/container_agent_env.yaml
Normal file
@ -0,0 +1,4 @@
|
||||
# Installs docker software-config agents on boot in a container
|
||||
|
||||
resource_registry:
|
||||
"Heat::InstallConfigAgent": templates/install_container_agent.yaml
|
@ -0,0 +1,18 @@
|
||||
#cloud-config
|
||||
merge_how: dict(recurse_array)+list(append)
|
||||
write_files:
|
||||
- path: /opt/container_agent/get_container_agent_image.sh
|
||||
owner: "root:root"
|
||||
permissions: "0644"
|
||||
content: |
|
||||
#!/bin/bash
|
||||
set -eux
|
||||
regex='(https?|http)://[-A-Za-z0-9\+&@#/%?=~_|!:,.;]*[-A-Za-z0-9\+&@#/%=~_|]'
|
||||
agent_image="$1"
|
||||
if [[ $agent_image =~ $regex ]]
|
||||
then
|
||||
cd /tmp && { curl $agent_image > heat_container_image.tar ; cd -; }
|
||||
/usr/bin/docker load -i /tmp/heat_container_image.tar
|
||||
else
|
||||
/usr/bin/docker pull $agent_image
|
||||
fi
|
@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
set -eux
|
||||
|
||||
# heat-docker-agent service
|
||||
cat <<EOF > /etc/systemd/system/heat-container-agent.service
|
||||
|
||||
[Unit]
|
||||
Description=Heat Container Agent
|
||||
After=docker.service
|
||||
Requires=docker.service
|
||||
|
||||
[Service]
|
||||
User=root
|
||||
Restart=on-failure
|
||||
ExecStartPre=-/usr/bin/docker kill heat-container-agent
|
||||
ExecStartPre=-/usr/bin/docker rm heat-container-agent
|
||||
ExecStartPre=/opt/agent_container/get_container_agent_image.sh $agent_image
|
||||
ExecStart=/usr/bin/docker run --name heat-container-agent --privileged --net=host -v /usr/bin/atomic:/usr/bin/atomic -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/atomic:/usr/bin/atomic -v /var/lib/cloud:/var/lib/cloud -v /var/lib/heat-cfntools:/var/lib/heat-cfntools $agent_image
|
||||
ExecStop=/usr/bin/docker stop heat-container-agent
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
EOF
|
||||
|
||||
# enable and start docker
|
||||
/usr/bin/systemctl enable docker.service
|
||||
/usr/bin/systemctl start --no-block docker.service
|
||||
|
||||
# enable and start heat-container-agent
|
||||
chmod 0640 /etc/systemd/system/heat-container-agent.service
|
||||
chmod 0755 /opt/agent_container/get_agent_container_image.sh
|
||||
/usr/bin/systemctl enable heat-container-agent.service
|
||||
/usr/bin/systemctl start --no-block heat-container-agent.service
|
@ -0,0 +1,33 @@
|
||||
heat_template_version: 2014-10-16
|
||||
|
||||
parameters:
|
||||
agent_image:
|
||||
type: string
|
||||
default: ramishra/heat-container-agent
|
||||
|
||||
resources:
|
||||
write_image_pull_script:
|
||||
type: "OS::Heat::SoftwareConfig"
|
||||
properties:
|
||||
group: ungrouped
|
||||
config: {get_file: ./fragments/get_container_agent_image.frag}
|
||||
|
||||
install_container_agent:
|
||||
type: OS::Heat::SoftwareConfig
|
||||
properties:
|
||||
group: script
|
||||
config:
|
||||
str_replace:
|
||||
params:
|
||||
$agent_image: {get_param: agent_image}
|
||||
template: {get_file: ./fragments/start_container_agent.sh}
|
||||
|
||||
node_init:
|
||||
type: "OS::Heat::MultipartMime"
|
||||
properties:
|
||||
parts:
|
||||
- config: {get_resource: write_image_pull_script}
|
||||
- config: {get_resource: install_container_agent}
|
||||
outputs:
|
||||
config:
|
||||
value: {get_resource: node_init}
|
@ -0,0 +1,98 @@
|
||||
heat_template_version: 2014-10-16
|
||||
description: >
|
||||
A template which demonstrates doing boot-time deployment of docker
|
||||
container with docker-compose agent.
|
||||
This template expects to be created with an environment which defines
|
||||
the resource type Heat::InstallConfigAgent such as
|
||||
../boot-config-docker/heat_docker_agents_env.yaml
|
||||
parameters:
|
||||
key_name:
|
||||
type: string
|
||||
default: heat_key
|
||||
flavor:
|
||||
type: string
|
||||
default: m1.small
|
||||
image:
|
||||
type: string
|
||||
default: fedora-atomic
|
||||
private_net:
|
||||
type: string
|
||||
default: private
|
||||
public_net:
|
||||
type: string
|
||||
default: public
|
||||
|
||||
resources:
|
||||
the_sg:
|
||||
type: OS::Neutron::SecurityGroup
|
||||
properties:
|
||||
name: the_sg
|
||||
description: Ping and SSH
|
||||
rules:
|
||||
- protocol: icmp
|
||||
- protocol: tcp
|
||||
port_range_min: 22
|
||||
port_range_max: 22
|
||||
- protocol: tcp
|
||||
port_range_min: 5000
|
||||
port_range_max: 5000
|
||||
|
||||
config:
|
||||
type: OS::Heat::StructuredConfig
|
||||
properties:
|
||||
group: docker-compose
|
||||
config:
|
||||
web:
|
||||
image: training/webapp
|
||||
ports:
|
||||
- 5000:5000
|
||||
|
||||
deployment:
|
||||
type: OS::Heat::StructuredDeployment
|
||||
properties:
|
||||
name: test_deployment
|
||||
config:
|
||||
get_resource: config
|
||||
server:
|
||||
get_resource: server
|
||||
|
||||
boot_config:
|
||||
type: Heat::InstallConfigAgent
|
||||
|
||||
server:
|
||||
type: OS::Nova::Server
|
||||
properties:
|
||||
image: {get_param: image}
|
||||
flavor: {get_param: flavor}
|
||||
key_name: {get_param: key_name}
|
||||
networks:
|
||||
- network: {get_param: private_net}
|
||||
security_groups:
|
||||
- {get_resource: the_sg}
|
||||
user_data_format: SOFTWARE_CONFIG
|
||||
user_data: {get_attr: [boot_config, config]}
|
||||
|
||||
server_floating_ip_assoc:
|
||||
type: OS::Neutron::FloatingIPAssociation
|
||||
properties:
|
||||
floatingip_id: {get_resource: floating_ip}
|
||||
port_id: {get_attr: [server, addresses, {get_param: private_net}, 0, port]}
|
||||
|
||||
floating_ip:
|
||||
type: OS::Neutron::FloatingIP
|
||||
properties:
|
||||
floating_network: {get_param: public_net}
|
||||
|
||||
outputs:
|
||||
result:
|
||||
value:
|
||||
get_attr: [deployment, result]
|
||||
stdout:
|
||||
value:
|
||||
get_attr: [deployment, deploy_stdout]
|
||||
stderr:
|
||||
value:
|
||||
get_attr: [deployment, deploy_stderr]
|
||||
status_code:
|
||||
value:
|
||||
get_attr: [deployment, deploy_status_code]
|
@ -0,0 +1,6 @@
|
||||
# Defines a Heat::InstallConfigAgent config resource which performs no config.
|
||||
# This environment can be used when the image already has the required agents
|
||||
# installed and configured.
|
||||
#
|
||||
resource_registry:
|
||||
"Heat::InstallConfigAgent": "OS::Heat::SoftwareConfig"
|
28
hot/software-config/heat-container-agent/Dockerfile
Normal file
28
hot/software-config/heat-container-agent/Dockerfile
Normal file
@ -0,0 +1,28 @@
|
||||
FROM fedora
|
||||
MAINTAINER “Rabi Mishra” <ramishra@redhat.com>
|
||||
ENV container docker
|
||||
|
||||
ADD ./scripts/55-heat-config \
|
||||
/opt/stack/os-config-refresh/configure.d/
|
||||
|
||||
ADD ./scripts/50-heat-config-docker-compose \
|
||||
/opt/stack/os-config-refresh/configure.d/
|
||||
|
||||
ADD ./scripts/* \
|
||||
/var/lib/heat-config/hooks/
|
||||
|
||||
ADD ./scripts/heat-config-notify \
|
||||
/usr/bin/heat-config-notify
|
||||
|
||||
ADD ./scripts/configure_container_agent.sh /tmp/
|
||||
RUN chmod 700 /tmp/configure_container_agent.sh ; \
|
||||
/tmp/configure_container_agent.sh
|
||||
|
||||
#create volumes to share the host directories
|
||||
VOLUME [ "/var/lib/cloud"]
|
||||
VOLUME [ "/var/lib/heat-cfntools" ]
|
||||
|
||||
#set DOCKER_HOST environment variable that docker-compose would use
|
||||
ENV DOCKER_HOST unix:///var/run/docker.sock
|
||||
|
||||
CMD /usr/bin/os-collect-config
|
16
hot/software-config/heat-container-agent/README.rst
Normal file
16
hot/software-config/heat-container-agent/README.rst
Normal file
@ -0,0 +1,16 @@
|
||||
=======================================================
|
||||
Steps to build container image with all container hooks
|
||||
=======================================================
|
||||
|
||||
Docker build does not work with soft links. Therefore, convert all
|
||||
soft links to hardlinks.
|
||||
|
||||
$ find -type l -exec bash -c 'ln -f "$(readlink -m "$0")" "$0"' {} \;
|
||||
|
||||
Build docker image with container hooks.
|
||||
|
||||
$docker build -t xxxx/heat-container-agent ./
|
||||
|
||||
Push the image to docker hub.
|
||||
|
||||
$docker push xxxx/heat-container-agent
|
@ -0,0 +1 @@
|
||||
../../elements/heat-config-docker-compose/os-refresh-config/configure.d/50-heat-config-docker-compose
|
1
hot/software-config/heat-container-agent/scripts/55-heat-config
Symbolic link
1
hot/software-config/heat-container-agent/scripts/55-heat-config
Symbolic link
@ -0,0 +1 @@
|
||||
../../elements/heat-config/os-refresh-config/configure.d/55-heat-config
|
116
hot/software-config/heat-container-agent/scripts/atomic
Normal file
116
hot/software-config/heat-container-agent/scripts/atomic
Normal file
@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import ast
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
WORKING_DIR = os.environ.get('HEAT_ATOMIC_WORKING',
|
||||
'/var/lib/heat-config/heat-config-atomic')
|
||||
ATOMIC_CMD = os.environ.get('HEAT_ATOMIC_CMD', 'atomic')
|
||||
|
||||
|
||||
def prepare_dir(path):
|
||||
if not os.path.isdir(path):
|
||||
os.makedirs(path, 0o700)
|
||||
|
||||
|
||||
def build_response(deploy_stdout, deploy_stderr, deploy_status_code):
|
||||
return {
|
||||
'deploy_stdout': deploy_stdout,
|
||||
'deploy_stderr': deploy_stderr,
|
||||
'deploy_status_code': deploy_status_code,
|
||||
}
|
||||
|
||||
|
||||
def main(argv=sys.argv):
|
||||
log = logging.getLogger('heat-config')
|
||||
handler = logging.StreamHandler(sys.stderr)
|
||||
handler.setFormatter(
|
||||
logging.Formatter(
|
||||
'[%(asctime)s] (%(name)s) [%(levelname)s] %(message)s'))
|
||||
log.addHandler(handler)
|
||||
log.setLevel('DEBUG')
|
||||
|
||||
c = json.load(sys.stdin)
|
||||
|
||||
prepare_dir(WORKING_DIR)
|
||||
os.chdir(WORKING_DIR)
|
||||
|
||||
env = os.environ.copy()
|
||||
|
||||
input_values = dict((i['name'], i['value']) for i in c['inputs'])
|
||||
|
||||
stdout, stderr = {}, {}
|
||||
config = c.get('config', '')
|
||||
if not config:
|
||||
log.debug("No 'config' input found, nothing to do.")
|
||||
json.dump(build_response(stdout, stderr, 0), sys.stdout)
|
||||
return
|
||||
|
||||
atomic_subcmd = config.get('command', 'install')
|
||||
image = config.get('image')
|
||||
|
||||
if input_values.get('deploy_action') == 'DELETE':
|
||||
cmd = [
|
||||
'uninstall',
|
||||
atomic_subcmd,
|
||||
image
|
||||
]
|
||||
subproc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE, env=env)
|
||||
stdout, stderr = subproc.communicate()
|
||||
|
||||
json.dump(build_response(stdout, stderr, subproc.returncode), sys.stdout)
|
||||
return
|
||||
|
||||
install_cmd = config.get('installcmd', '')
|
||||
name = config.get('name', c.get('id'))
|
||||
|
||||
cmd = [
|
||||
ATOMIC_CMD,
|
||||
atomic_subcmd,
|
||||
image,
|
||||
'-n %s' % name
|
||||
]
|
||||
|
||||
if atomic_subcmd == 'install':
|
||||
cmd.extend([install_cmd])
|
||||
|
||||
privileged = config.get('privileged', False)
|
||||
|
||||
if atomic_subcmd == 'run' and privileged:
|
||||
cmd.extend(['--spc'])
|
||||
|
||||
log.debug('Running %s' % cmd)
|
||||
|
||||
subproc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
stdout, stderr = subproc.communicate()
|
||||
|
||||
log.debug(stdout)
|
||||
log.debug(stderr)
|
||||
|
||||
if subproc.returncode:
|
||||
log.error("Error running %s. [%s]\n" % (cmd, subproc.returncode))
|
||||
else:
|
||||
log.debug('Completed %s' % cmd)
|
||||
|
||||
json.dump(build_response(stdout, stderr, subproc.returncode), sys.stdout)
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv))
|
@ -0,0 +1,111 @@
|
||||
#!/bin/bash
|
||||
set -eux
|
||||
|
||||
yum -y update
|
||||
|
||||
yum -y install os-collect-config os-apply-config \
|
||||
os-refresh-config dib-utils python-pip python-docker-py
|
||||
|
||||
yum clean all
|
||||
|
||||
# pip installing dpath as python-dpath is an older version of dpath
|
||||
pip install dpath
|
||||
|
||||
# using binary as 'docker-compose' and 'os-collect-config' has conflict on 'requests' version
|
||||
# os-collect-config requires 2.5.3 where as for docker-compose it's <2.5.0
|
||||
curl -L https://github.com/docker/compose/releases/download/1.1.0/docker-compose-`uname -s`-`uname -m` \
|
||||
> /usr/local/bin/docker-compose
|
||||
|
||||
# os-apply-config templates directory
|
||||
oac_templates=/usr/libexec/os-apply-config/templates
|
||||
mkdir -p $oac_templates/etc
|
||||
|
||||
# initial /etc/os-collect-config.conf
|
||||
cat <<EOF >/etc/os-collect-config.conf
|
||||
[DEFAULT]
|
||||
command = os-refresh-config
|
||||
EOF
|
||||
|
||||
# template for building os-collect-config.conf for polling heat
|
||||
cat <<EOF >$oac_templates/etc/os-collect-config.conf
|
||||
[DEFAULT]
|
||||
{{^os-collect-config.command}}
|
||||
command = os-refresh-config
|
||||
{{/os-collect-config.command}}
|
||||
{{#os-collect-config}}
|
||||
{{#command}}
|
||||
command = {{command}}
|
||||
{{/command}}
|
||||
{{#polling_interval}}
|
||||
polling_interval = {{polling_interval}}
|
||||
{{/polling_interval}}
|
||||
{{#cachedir}}
|
||||
cachedir = {{cachedir}}
|
||||
{{/cachedir}}
|
||||
{{#collectors}}
|
||||
collectors = {{collectors}}
|
||||
{{/collectors}}
|
||||
|
||||
{{#cfn}}
|
||||
[cfn]
|
||||
{{#metadata_url}}
|
||||
metadata_url = {{metadata_url}}
|
||||
{{/metadata_url}}
|
||||
stack_name = {{stack_name}}
|
||||
secret_access_key = {{secret_access_key}}
|
||||
access_key_id = {{access_key_id}}
|
||||
path = {{path}}
|
||||
{{/cfn}}
|
||||
|
||||
{{#heat}}
|
||||
[heat]
|
||||
auth_url = {{auth_url}}
|
||||
user_id = {{user_id}}
|
||||
password = {{password}}
|
||||
project_id = {{project_id}}
|
||||
stack_id = {{stack_id}}
|
||||
resource_name = {{resource_name}}
|
||||
{{/heat}}
|
||||
|
||||
{{#request}}
|
||||
[request]
|
||||
{{#metadata_url}}
|
||||
metadata_url = {{metadata_url}}
|
||||
{{/metadata_url}}
|
||||
{{/request}}
|
||||
|
||||
{{/os-collect-config}}
|
||||
EOF
|
||||
mkdir -p $oac_templates/var/run/heat-config
|
||||
|
||||
# template for writing heat deployments data to a file
|
||||
echo "{{deployments}}" > $oac_templates/var/run/heat-config/heat-config
|
||||
|
||||
# os-refresh-config scripts directory
|
||||
# This moves to /usr/libexec/os-refresh-config in later releases
|
||||
orc_scripts=/opt/stack/os-config-refresh
|
||||
for d in pre-configure.d configure.d migration.d post-configure.d; do
|
||||
install -m 0755 -o root -g root -d $orc_scripts/$d
|
||||
done
|
||||
|
||||
# os-refresh-config script for running os-apply-config
|
||||
cat <<EOF >$orc_scripts/configure.d/20-os-apply-config
|
||||
#!/bin/bash
|
||||
set -ue
|
||||
|
||||
exec os-apply-config
|
||||
EOF
|
||||
chmod 700 $orc_scripts/configure.d/20-os-apply-config
|
||||
|
||||
# create hooks directory
|
||||
#hooks_dir=/var/lib/heat-config/hooks
|
||||
#mkdir -p $hooks_dir
|
||||
|
||||
chmod 700 /opt/stack/os-config-refresh/configure.d/55-heat-config
|
||||
chmod 700 /opt/stack/os-config-refresh/configure.d/50-heat-config-docker-compose
|
||||
|
||||
chmod 755 /var/lib/heat-config/hooks/atomic
|
||||
chmod 755 /var/lib/heat-config/hooks/docker-compose
|
||||
chmod 755 /var/lib/heat-config/hooks/script
|
||||
|
||||
chmod 755 /usr/bin/heat-config-notify
|
1
hot/software-config/heat-container-agent/scripts/docker-compose
Symbolic link
1
hot/software-config/heat-container-agent/scripts/docker-compose
Symbolic link
@ -0,0 +1 @@
|
||||
../../elements/heat-config-docker-compose/install.d/hook-docker-compose.py
|
@ -0,0 +1 @@
|
||||
../../elements/heat-config/bin/heat-config-notify
|
1
hot/software-config/heat-container-agent/scripts/script
Symbolic link
1
hot/software-config/heat-container-agent/scripts/script
Symbolic link
@ -0,0 +1 @@
|
||||
../../elements/heat-config-script/install.d/hook-script.py
|
Loading…
Reference in New Issue
Block a user