OpenStack
and
Inside and Out
Florian Haas, florian@hastexo.com
A few
to start with
You should
OpenStack
- This talk assumes familiarity with basic OpenStack concepts. - It is not for OpenStack novices.You're welcome to
You'll
an OpenStack environment
- Following along requires that you currently have access to an OpenStack cluster via its Keystone, Nova, Glance and Neutron APIs (first part) and also via the Heat API (second part).If you're
or
to follow along,
Just listen and participate in the discussion.
- If you do not have access to your own cluster right now, you can still follow along, ask questions, poke holes in my templates, and try the material next time you're back at the office.Let's talk about
can we automate
in OpenStack?
Nova
nova boot \ --image trusty-server-cloudimg-amd64 \ --key_name mykey \ --flavor m1.small \ --user-data userdata.txt \ --nic net-id=4f0dcc21-4b6c-47db-b283-591fdb9aa5a7 \ test0
is what user-data
looks like:
#!/bin/sh -e # Frobnicate a newly booted box initialize_box for foo in frobnications; do frobnicate_machine $foo || break done exit $?
You can do
Enter
enables you to
a newly booted VM
cloud-config is 100%
cloud-config is OpenStack's most
feature
cloud-config is Ubuntu's most
feature
What can we
with cloud-config?
Update system on first boot
#cloud-config package_update: true package_upgrade: true
Configure users and groups
users: - default - name: foobar gecos: "Fred Otto Oscar Bar" groups: users,adm lock-passwd: false passwd: $6$rounds=4096$J86aZz0Q$To16RGzWJku0 shell: /bin/bash sudo: "ALL=(ALL) NOPASSWD:ALL"
Enable/disable SSH password authentication
ssh_pwauth: true
Write arbitrary files
write_files: - path: /etc/hosts permissions: '0644' content: | 127.0.0.1 localhost ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 192.168.122.100 deploy.example.com deploy 192.168.122.111 alice.example.com alice 192.168.122.112 bob.example.com bob 192.168.122.113 charlie.example.com charlie
Configure a VM's Puppet agent
puppet: conf: agent: server: "puppetmaster.example.org" certname: "%i.%f" ca_cert: | -----BEGIN CERTIFICATE----- MIICCTCCAXKgAwIBAgIBATANBgkqhkiG9w0BAQUFADANMQswCQYDVQQDDAJjYTAe Fw0xMDAyMTUxNzI5MjFaFw0xNTAyMTQxNzI5MjFaMA0xCzAJBgNVBAMMAmNhMIGf MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCu7Q40sm47/E1Pf+r8AYb/V/FWGPgc b014OmNoX7dgCxTDvps/h8Vw555PdAFsW5+QhsGr31IJNI3kSYprFQcYf7A8tNWu SIb3DQEBBQUAA4GBAH/rxlUIjwNb3n7TXJcDJ6MMHUlwjr03BDJXKb34Ulndkpaf +GAlzPXWa7bO908M9I8RnPfvtKnteLbvgTK+h+zX1XCty+S2EQWk29i2AdoqOTxb hppiGMp0tT5Havu4aceCXiy2crVcudj3NFciy8X66SoECemW9UYDCb9T5D0d -----END CERTIFICATE-----
Configure a VM's Chef client
chef: install_type: "packages" force_install: false server_url: "https://chef.yourorg.com:4000" node_name: "your-node-name" environment: "production" validation_name: "yourorg-validator" validation_key: | -----BEGIN RSA PRIVATE KEY----- YOUR-ORGS-VALIDATION-KEY-HERE -----END RSA PRIVATE KEY----- run_list: - "recipe[apache2]" - "role[db]" initial_attributes: apache: prefork: maxclients: 100 keepalive: "off"
Install packages
packages: - ansible - git
Running
Run commands early in the boot sequence
bootcmd: - ntpdate pool.ntp.org
Run commands late in the boot sequence
runcmd: - > sudo -i -u training ansible-pull -v -i hosts -U https://github.com/hastexo/academy-ansible -o site.yml
(not an acronym)
enables you to deploy
virtual environments
supports two distinct
Amazon CloudFormation compatible template
Heat Orchestration Template
HOT is 100%
What can we
with Heat?
Configures Nova guests
resources: mybox: type: "OS::Nova::Server" properties: name: mybox image: trusty-server-cloudimg-amd64 flavor: m1.small key_name: mykey
Now we could just
this stack
heat stack-create -f stack.yml mystack
But as it is,
it's not very
Let's add some
parameters: flavor: type: string description: Flavor to use for servers default: m1.medium image: type: string description: Image name or ID default: trusty-server-cloudimg-amd64 key_name: type: string description: Keypair to inject into newly created servers
And some
resources: mybox: type: "OS::Nova::Server" properties: name: mybox image: { get_param: image } flavor: { get_param: flavor } key_name: { get_param: key_name }
And now we can
these parameters
heat stack-create -f stack.yml \ -P key_name=mykey -P image=cirros-0.3.3-x86_64 \ mystack
How about we add some
Wouldn't that be nice?
Defines Neutron networks
mynet: type: "OS::Neutron::Net" properties: name: management-net mysub_net: type: "OS::Neutron::Subnet" properties: name: management-sub-net network: { get_resource: management_net } cidr: 192.168.122.0/24 gateway_ip: 192.168.101.1 enable_dhcp: true allocation_pools: - start: "192.168.101.2" end: "192.168.101.50"
Cross-reference between resources
Automatic dependency
Configures Neutron routers
parameters: public_net: type: string description: Public network ID or name resources: router: type: OS::Neutron::Router router_gateway: type: OS::Neutron::RouterGateway properties: router: { get_resource: router } network: { get_param: public_net } router_interface: type: OS::Neutron::RouterInterface properties: router: { get_resource: router } subnet: { get_resource: mysub_net }
Configures Neutron ports
mybox_management_port: type: "OS::Neutron::Port" properties: network: { get_resource: mynet }
mybox: type: "OS::Nova::Server" properties: name: deploy image: { get_param: image } flavor: { get_param: flavor } key_name: { get_param: key_name } networks: - port: { get_resource: mybox_management_port }
Configures Neutron security groups
mysecurity_group: type: OS::Neutron::SecurityGroup properties: description: Neutron security group rules name: mysecurity_group rules: - remote_ip_prefix: 0.0.0.0/0 protocol: tcp port_range_min: 22 port_range_max: 22 - remote_ip_prefix: 0.0.0.0/0 protocol: icmp direction: ingress
mybox_management_port: type: "OS::Neutron::Port" properties: network: { get_resource: mynet } security_groups: - { get_resource: mysecurity_group }
Allocates floating IP addresses
myfloating_ip: type: "OS::Neutron::FloatingIP" properties: floating_network: { get_param: public_net } port: { get_resource: mybox_management_port }
Return stack values or attributes
outputs: public_ip: description: Floating IP address in public network value: { get_attr: [ myfloating_ip, floating_ip_address ] }
heat output-show \ mystack public_ip
Integrating
with
mybox: type: "OS::Nova::Server" properties: name: deploy image: { get_param: image } flavor: { get_param: flavor } key_name: { get_param: key_name } networks: - port: { get_resource: mybox_management_port } user_data: { get_file: cloud-config.yml } user_data_format: RAW
Manages cloud-config directly from Heat
resources: myconfig: type: "OS::Heat::CloudConfig" properties: cloud_config: package_update: true package_upgrade: true
mybox: type: "OS::Nova::Server" properties: name: deploy image: { get_param: image } flavor: { get_param: flavor } key_name: { get_param: key_name } networks: - port: { get_resource: mybox_management_port } user_data: { get_resource: myconfig } user_data_format: RAW
Now we can also
directly from Heat
parameters: # [...] username: type: string description: Additional login username default: foobar gecos: type: string description: Additional user full name default: ''
myconfig: type: "OS::Heat::CloudConfig" properties: cloud_config: package_update: true package_upgrade: true users: - default - name: { get_param: username } gecos: { get_param: gecos } groups: "users,adm" lock-passwd: false passwd: '$6$WP9924IJiLSto8Ng$MSDwCvlT28jM' shell: "/bin/bash" sudo: "ALL=(ALL) NOPASSWD:ALL" ssh_pwauth: true
You've just built a Heat/cloud-config enabled stack!
http://bazaar.launchpad.net/~cloud-init-dev/cloud-init/trunk/files/head:/doc/examples/