diff options
-rw-r--r-- | playbooks/provisioning/openstack/README.md | 41 | ||||
-rw-r--r-- | playbooks/provisioning/openstack/sample-inventory/group_vars/all.yml | 34 | ||||
-rw-r--r-- | playbooks/provisioning/openstack/stack_params.yaml | 26 | ||||
-rw-r--r-- | roles/openstack-stack/defaults/main.yml | 1 | ||||
-rw-r--r-- | roles/openstack-stack/templates/heat_stack.yaml.j2 | 50 | ||||
-rw-r--r-- | roles/openstack-stack/templates/heat_stack_server.yaml.j2 | 1 | ||||
-rw-r--r-- | roles/openstack-stack/templates/heat_stack_server_nofloating.yaml.j2 | 1 | ||||
-rw-r--r-- | roles/static_inventory/defaults/main.yml | 8 | ||||
-rw-r--r-- | roles/static_inventory/tasks/main.yml | 7 | ||||
-rw-r--r-- | roles/static_inventory/tasks/openstack.yml | 20 | ||||
-rw-r--r-- | roles/static_inventory/tasks/sshtun.yml | 15 | ||||
-rw-r--r-- | roles/static_inventory/templates/ssh-tunnel.service.j2 | 20 |
12 files changed, 187 insertions, 37 deletions
diff --git a/playbooks/provisioning/openstack/README.md b/playbooks/provisioning/openstack/README.md index c7b2ea975..afaeb430b 100644 --- a/playbooks/provisioning/openstack/README.md +++ b/playbooks/provisioning/openstack/README.md @@ -78,6 +78,10 @@ your servers will be under. With the default values, this will be That sudomain can be set as well by the `openshift_app_domain` variable in the inventory. +The `openstack_<role name>_hostname` is a set of variables used for customising +hostnames of servers with a given role. When such a variable stays commented, +default hostname (usually the role name) is used. + The `public_dns_nameservers` is a list of DNS servers accessible from all the created Nova servers. These will be serving as your DNS forwarders for external FQDNs that do not belong to the cluster's DNS domain and its subdomains. @@ -98,18 +102,29 @@ as a default nameserver that comes from the NetworkManager and cloud-init. `openstack keypair list`. This guide assumes that its corresponding private key is `~/.ssh/openshift`, stored on the ansible admin (control) node. -`openstack_default_image_name` is the name of the Glance image the -servers will use. You can -see your images with `openstack image list`. +`openstack_default_image_name` is the default name of the Glance image the +servers will use. You can see your images with `openstack image list`. +In order to set a different image for a role, uncomment the line with the +corresponding variable (e.g. `openstack_lb_image_name` for load balancer) and +set its value to another available image name. `openstack_default_image_name` +must stay defined as it is used as a default value for the rest of the roles. -`openstack_default_flavor` is the Nova flavor the servers will use. +`openstack_default_flavor` is the default Nova flavor the servers will use. You can see your flavors with `openstack flavor list`. +In order to set a different flavor for a role, uncomment the line with the +corresponding variable (e.g. `openstack_lb_flavor` for load balancer) and +set its value to another available flavor. `openstack_default_flavor` must +stay defined as it is used as a default value for the rest of the roles. `openstack_external_network_name` is the name of the Neutron network providing external connectivity. It is often called `public`, `external` or `ext-net`. You can see your networks with `openstack network list`. +`openstack_private_network_name` is the name of the private Neutron network +providing admin/control access for ansible. It can be merged with other +cluster networks, there are no special requirements for networking. + The `openstack_num_masters`, `openstack_num_infra` and `openstack_num_nodes` values specify the number of Master, Infra and App nodes to create. @@ -240,6 +255,24 @@ Once it succeeds, you can install openshift by running: ansible-playbook openshift-ansible/playbooks/byo/config.yml +### Access UI + +OpenShift UI may be accessed via the 1st master node FQDN, port 8443. + +When using a bastion, you may want to make an SSH tunnel from your control node +to access UI on the `https://localhost:8443`, with this inventory variable: + + openshift_ui_ssh_tunnel: True + +Note, this requires sudo rights on the ansible control node and an absolute path +for the `openstack_private_ssh_key`. You should also update the control node's +`/etc/hosts`: + + 127.0.0.1 master-0.openshift.example.com + +In order to access UI, the ssh-tunnel service will be created and started on the +control node. Make sure to remove these changes and the service manually, when not +needed anymore. ## License diff --git a/playbooks/provisioning/openstack/sample-inventory/group_vars/all.yml b/playbooks/provisioning/openstack/sample-inventory/group_vars/all.yml index 8f337546c..19f916508 100644 --- a/playbooks/provisioning/openstack/sample-inventory/group_vars/all.yml +++ b/playbooks/provisioning/openstack/sample-inventory/group_vars/all.yml @@ -3,15 +3,45 @@ env_id: "openshift" public_dns_domain: "example.com" public_dns_nameservers: [] +# # Used Hostnames +# # - set custom hostnames for roles by uncommenting corresponding lines +#openstack_master_hostname: "master" +#openstack_infra_hostname: "infra-node" +#openstack_node_hostname: "app-node" +#openstack_lb_hostname: "lb" +#openstack_etcd_hostname: "etcd" +#openstack_dns_hostname: "dns" + openstack_ssh_public_key: "openshift" -openstack_default_image_name: "centos7" -openstack_default_flavor: "m1.medium" openstack_external_network_name: "public" +#openstack_private_network_name: "openshift-ansible-{{ stack_name }}-net" + +# # Used Images +# # - set specific images for roles by uncommenting corresponding lines +# # - note: do not remove openstack_default_image_name definition +#openstack_master_image_name: "centos7" +#openstack_infra_image_name: "centos7" +#openstack_node_image_name: "centos7" +#openstack_lb_image_name: "centos7" +#openstack_etcd_image_name: "centos7" +#openstack_dns_image_name: "centos7" +openstack_default_image_name: "centos7" openstack_num_masters: 1 openstack_num_infra: 1 openstack_num_nodes: 2 +# # Used Flavors +# # - set specific flavors for roles by uncommenting corresponding lines +# # - note: do note remove openstack_default_flavor definition +#openstack_master_flavor: "m1.medium" +#openstack_infra_flavor: "m1.medium" +#openstack_node_flavor: "m1.medium" +#openstack_lb_flavor: "m1.medium" +#openstack_etcd_flavor: "m1.medium" +#openstack_dns_flavor: "m1.medium" +openstack_default_flavor: "m1.medium" + # # Numerical index of nodes to remove # openstack_nodes_to_remove: [] diff --git a/playbooks/provisioning/openstack/stack_params.yaml b/playbooks/provisioning/openstack/stack_params.yaml index c3a42ab06..27fa5ec8c 100644 --- a/playbooks/provisioning/openstack/stack_params.yaml +++ b/playbooks/provisioning/openstack/stack_params.yaml @@ -3,14 +3,27 @@ stack_name: "{{ env_id }}.{{ public_dns_domain }}" dns_domain: "{{ public_dns_domain }}" dns_nameservers: "{{ public_dns_nameservers }}" subnet_prefix: "{{ openstack_subnet_prefix }}" +master_hostname: "{{ openstack_master_hostname | default('master') }}" +infra_hostname: "{{ openstack_infra_hostname | default('infra-node') }}" +node_hostname: "{{ openstack_node_hostname | default('app-node') }}" +lb_hostname: "{{ openstack_lb_hostname | default('lb') }}" +etcd_hostname: "{{ openstack_etcd_hostname | default('etcd') }}" +dns_hostname: "{{ openstack_dns_hostname | default('dns') }}" ssh_public_key: "{{ openstack_ssh_public_key }}" openstack_image: "{{ openstack_default_image_name }}" -lb_flavor: "{{ openstack_default_flavor | default('m1.small') }}" -etcd_flavor: "{{ openstack_default_flavor | default('m1.small') }}" -master_flavor: "{{ openstack_default_flavor | default('m1.medium') }}" -node_flavor: "{{ openstack_default_flavor | default('m1.medium') }}" -infra_flavor: "{{ openstack_default_flavor | default('m1.medium') }}" -dns_flavor: "{{ openstack_default_flavor | default('m1.small') }}" +lb_flavor: "{{ openstack_lb_flavor | default(openstack_default_flavor) }}" +etcd_flavor: "{{ openstack_etcd_flavor | default(openstack_default_flavor) }}" +master_flavor: "{{ openstack_master_flavor | default(openstack_default_flavor) }}" +node_flavor: "{{ openstack_node_flavor | default(openstack_default_flavor) }}" +infra_flavor: "{{ openstack_infra_flavor | default(openstack_default_flavor) }}" +dns_flavor: "{{ openstack_dns_flavor | default(openstack_default_flavor) }}" +openstack_master_image: "{{ openstack_master_image_name | default(openstack_default_image_name) }}" +openstack_infra_image: "{{ openstack_infra_image_name | default(openstack_default_image_name) }}" +openstack_node_image: "{{ openstack_node_image_name | default(openstack_default_image_name) }}" +openstack_lb_image: "{{ openstack_lb_image_name | default(openstack_default_image_name) }}" +openstack_etcd_image: "{{ openstack_etcd_image_name | default(openstack_default_image_name) }}" +openstack_dns_image: "{{ openstack_dns_image_name | default(openstack_default_image_name) }}" +openstack_private_network: "{{ openstack_private_network_name | default ('openshift-ansible-' + stack_name + '-net') }}" external_network: "{{ openstack_external_network_name }}" num_etcd: "{{ openstack_num_etcd | default(0) }}" num_masters: "{{ openstack_num_masters }}" @@ -22,3 +35,4 @@ app_volume_size: "{{ docker_volume_size }}" infra_volume_size: "{{ docker_volume_size }}" nodes_to_remove: "{{ openstack_nodes_to_remove | default([]) | to_yaml }}" use_bastion: "{{ openstack_use_bastion|default(False) }}" +ui_ssh_tunnel: "{{ openshift_ui_ssh_tunnel|default(False) }}" diff --git a/roles/openstack-stack/defaults/main.yml b/roles/openstack-stack/defaults/main.yml index 803a96389..c8529612e 100644 --- a/roles/openstack-stack/defaults/main.yml +++ b/roles/openstack-stack/defaults/main.yml @@ -13,3 +13,4 @@ num_infra: 1 nodes_to_remove: [] etcd_volume_size: 2 use_bastion: False +ui_ssh_tunnel: False diff --git a/roles/openstack-stack/templates/heat_stack.yaml.j2 b/roles/openstack-stack/templates/heat_stack.yaml.j2 index 524f466ff..3623035c6 100644 --- a/roles/openstack-stack/templates/heat_stack.yaml.j2 +++ b/roles/openstack-stack/templates/heat_stack.yaml.j2 @@ -439,7 +439,7 @@ resources: port_range_min: 53 port_range_max: 53 remote_ip_prefix: "{{ openstack_subnet_prefix }}.0/24" -{% if num_masters > 1 %} +{% if num_masters > 1 or ui_ssh_tunnel|bool %} lb-secgrp: type: OS::Neutron::SecurityGroup properties: @@ -450,14 +450,21 @@ resources: protocol: tcp port_range_min: {{ openshift_master_api_port | default(8443) }} port_range_max: {{ openshift_master_api_port | default(8443) }} - remote_ip_prefix: {{ lb_ingress_cidr }} - {% if openshift_master_console_port is defined and openshift_master_console_port != openshift_master_api_port %} + remote_ip_prefix: {{ lb_ingress_cidr | default(bastion_ingress_cidr) }} +{% if ui_ssh_tunnel|bool %} + - direction: ingress + protocol: tcp + port_range_min: {{ openshift_master_api_port | default(8443) }} + port_range_max: {{ openshift_master_api_port | default(8443) }} + remote_ip_prefix: {{ ssh_ingress_cidr }} +{% endif %} +{% if openshift_master_console_port is defined and openshift_master_console_port != openshift_master_api_port %} - direction: ingress protocol: tcp port_range_min: {{ openshift_master_console_port | default(8443) }} port_range_max: {{ openshift_master_console_port | default(8443) }} - remote_ip_prefix: {{ lb_ingress_cidr }} - {% endif %} + remote_ip_prefix: {{ lb_ingress_cidr | default(bastion_ingress_cidr) }} +{% endif %} {% endif %} etcd: @@ -476,7 +483,7 @@ resources: template: k8s_type-%index%.cluster_id params: cluster_id: {{ stack_name }} - k8s_type: etcd + k8s_type: {{ etcd_hostname }} cluster_env: {{ public_dns_domain }} cluster_id: {{ stack_name }} group: @@ -486,7 +493,7 @@ resources: k8s_type: etcds cluster_id: {{ stack_name }} type: etcd - image: {{ openstack_image }} + image: {{ openstack_etcd_image }} flavor: {{ etcd_flavor }} key_name: {{ ssh_public_key }} net: { get_resource: net } @@ -519,7 +526,7 @@ resources: template: k8s_type-%index%.cluster_id params: cluster_id: {{ stack_name }} - k8s_type: lb + k8s_type: {{ lb_hostname }} cluster_env: {{ public_dns_domain }} cluster_id: {{ stack_name }} group: @@ -529,7 +536,7 @@ resources: k8s_type: lb cluster_id: {{ stack_name }} type: lb - image: {{ openstack_image }} + image: {{ openstack_lb_image }} flavor: {{ lb_flavor }} key_name: {{ ssh_public_key }} net: { get_resource: net } @@ -564,7 +571,7 @@ resources: template: k8s_type-%index%.cluster_id params: cluster_id: {{ stack_name }} - k8s_type: master + k8s_type: {{ master_hostname }} cluster_env: {{ public_dns_domain }} cluster_id: {{ stack_name }} group: @@ -574,7 +581,7 @@ resources: k8s_type: masters cluster_id: {{ stack_name }} type: master - image: {{ openstack_image }} + image: {{ openstack_master_image }} flavor: {{ master_flavor }} key_name: {{ ssh_public_key }} net: { get_resource: net } @@ -617,11 +624,10 @@ resources: properties: name: str_replace: - template: subtype-k8s_type-%index%.cluster_id + template: sub_type_k8s_type-%index%.cluster_id params: cluster_id: {{ stack_name }} - k8s_type: node - subtype: app + sub_type_k8s_type: {{ node_hostname }} cluster_env: {{ public_dns_domain }} cluster_id: {{ stack_name }} group: @@ -636,7 +642,7 @@ resources: {% for k, v in openshift_cluster_node_labels.app.iteritems() %} {{ k|e }}: {{ v|e }} {% endfor %} - image: {{ openstack_image }} + image: {{ openstack_node_image }} flavor: {{ node_flavor }} key_name: {{ ssh_public_key }} net: { get_resource: net } @@ -665,11 +671,10 @@ resources: properties: name: str_replace: - template: subtypek8s_type-%index%.cluster_id + template: sub_type_k8s_type-%index%.cluster_id params: cluster_id: {{ stack_name }} - k8s_type: node - subtype: infra + sub_type_k8s_type: {{ infra_hostname }} cluster_env: {{ public_dns_domain }} cluster_id: {{ stack_name }} group: @@ -684,7 +689,7 @@ resources: {% for k, v in openshift_cluster_node_labels.infra.iteritems() %} {{ k|e }}: {{ v|e }} {% endfor %} - image: {{ openstack_image }} + image: {{ openstack_infra_image }} flavor: {{ infra_flavor }} key_name: {{ ssh_public_key }} net: { get_resource: net } @@ -696,6 +701,9 @@ resources: {% else %} - { get_resource: node-secgrp } {% endif %} +{% if ui_ssh_tunnel|bool and num_masters < 2 %} + - { get_resource: lb-secgrp } +{% endif %} - { get_resource: infra-secgrp } - { get_resource: common-secgrp } floating_network: {{ external_network }} @@ -720,7 +728,7 @@ resources: template: k8s_type-%index%.cluster_id params: cluster_id: {{ stack_name }} - k8s_type: dns + k8s_type: {{ dns_hostname }} cluster_env: {{ public_dns_domain }} cluster_id: {{ stack_name }} group: @@ -730,7 +738,7 @@ resources: k8s_type: dns cluster_id: {{ stack_name }} type: dns - image: {{ openstack_image }} + image: {{ openstack_dns_image }} flavor: {{ dns_flavor }} key_name: {{ ssh_public_key }} net: { get_resource: net } diff --git a/roles/openstack-stack/templates/heat_stack_server.yaml.j2 b/roles/openstack-stack/templates/heat_stack_server.yaml.j2 index 85af311ec..32fb166f6 100644 --- a/roles/openstack-stack/templates/heat_stack_server.yaml.j2 +++ b/roles/openstack-stack/templates/heat_stack_server.yaml.j2 @@ -134,6 +134,7 @@ resources: user_data: get_file: user-data user_data_format: RAW + user_data_update_policy: IGNORE metadata: group: { get_param: group } environment: { get_param: cluster_env } diff --git a/roles/openstack-stack/templates/heat_stack_server_nofloating.yaml.j2 b/roles/openstack-stack/templates/heat_stack_server_nofloating.yaml.j2 index a22b7c6d0..638fc8b45 100644 --- a/roles/openstack-stack/templates/heat_stack_server_nofloating.yaml.j2 +++ b/roles/openstack-stack/templates/heat_stack_server_nofloating.yaml.j2 @@ -119,6 +119,7 @@ resources: user_data: get_file: user-data user_data_format: RAW + user_data_update_policy: IGNORE metadata: group: { get_param: group } environment: { get_param: cluster_env } diff --git a/roles/static_inventory/defaults/main.yml b/roles/static_inventory/defaults/main.yml index 63de45646..871700f8c 100644 --- a/roles/static_inventory/defaults/main.yml +++ b/roles/static_inventory/defaults/main.yml @@ -19,3 +19,11 @@ private_ssh_key: ~/.ssh/openshift # The patch to store the generated config to access bastion/hosts ssh_config_path: /tmp/ssh.config.ansible + +# The IP:port to make an SSH tunnel to access UI on the 1st master +# via bastion node (requires sudo on the ansible control node) +ui_ssh_tunnel: False +ui_port: "{{ openshift_master_api_port | default(8443) }}" +target_ip: "{{ hostvars[groups['masters.' + stack_name|quote][0]].private_v4 }}" + +openstack_private_network: private diff --git a/roles/static_inventory/tasks/main.yml b/roles/static_inventory/tasks/main.yml index b58866017..24e11beb6 100644 --- a/roles/static_inventory/tasks/main.yml +++ b/roles/static_inventory/tasks/main.yml @@ -8,3 +8,10 @@ - name: Generate SSH config for accessing hosts via bastion include: sshconfig.yml when: use_bastion|bool + +- name: Configure SSH tunneling to access UI + include: sshtun.yml + become: true + when: + - use_bastion|bool + - ui_ssh_tunnel|bool diff --git a/roles/static_inventory/tasks/openstack.yml b/roles/static_inventory/tasks/openstack.yml index 499adf08c..75d0ee6d5 100644 --- a/roles/static_inventory/tasks/openstack.yml +++ b/roles/static_inventory/tasks/openstack.yml @@ -29,12 +29,20 @@ add_host: name: '{{ item.name }}' groups: '{{ item.metadata.group }}' - ansible_host: "{% if use_bastion|bool %}{{ item.name }}{% else %}{{ item.private_v4 }}{% endif %}" + ansible_host: >- + {% if use_bastion|bool -%} + {{ item.name }} + {%- else -%} + {%- set node = registered_nodes | json_query("[?name=='" + item.name + "']") -%} + {{ node[0].addresses[openstack_private_network|quote][0].addr }} + {%- endif %} ansible_fqdn: '{{ item.name }}' ansible_user: '{{ ssh_user }}' ansible_private_key_file: '{{ private_ssh_key }}' ansible_ssh_extra_args: '-F {{ ssh_config_path }}' - private_v4: '{{ item.private_v4 }}' + private_v4: >- + {% set node = registered_nodes | json_query("[?name=='" + item.name + "']") -%} + {{ node[0].addresses[openstack_private_network|quote][0].addr }} - name: Add cluster nodes with floating IPs to inventory with_items: "{{ registered_nodes_floating }}" @@ -46,7 +54,9 @@ ansible_user: '{{ ssh_user }}' ansible_private_key_file: '{{ private_ssh_key }}' ansible_ssh_extra_args: '-F {{ ssh_config_path }}' - private_v4: '{{ item.private_v4 }}' + private_v4: >- + {% set node = registered_nodes | json_query("[?name=='" + item.name + "']") -%} + {{ node[0].addresses[openstack_private_network|quote][0].addr }} public_v4: '{{ item.public_v4 }}' - name: Add bastion node to inventory @@ -58,7 +68,9 @@ ansible_user: '{{ ssh_user }}' ansible_private_key_file: '{{ private_ssh_key }}' ansible_ssh_extra_args: '-F {{ ssh_config_path }}' - private_v4: '{{ registered_bastion_nodes[0].private_v4 }}' + private_v4: >- + {% set node = registered_nodes | json_query("[?name=='" + registered_bastion_nodes[0].name + "']") -%} + {{ node[0].addresses[openstack_private_network|quote][0].addr }} public_v4: '{{ registered_bastion_nodes[0].public_v4 }}' when: - registered_bastion_nodes is defined diff --git a/roles/static_inventory/tasks/sshtun.yml b/roles/static_inventory/tasks/sshtun.yml new file mode 100644 index 000000000..b0e4c832c --- /dev/null +++ b/roles/static_inventory/tasks/sshtun.yml @@ -0,0 +1,15 @@ +--- +- name: Create ssh tunnel systemd service + template: + src: ssh-tunnel.service.j2 + dest: /etc/systemd/system/ssh-tunnel.service + mode: 0644 + +- name: reload the systemctl daemon after file update + command: systemctl daemon-reload + +- name: Enable ssh tunnel service + service: + name: ssh-tunnel + enabled: true + state: restarted diff --git a/roles/static_inventory/templates/ssh-tunnel.service.j2 b/roles/static_inventory/templates/ssh-tunnel.service.j2 new file mode 100644 index 000000000..0d1cf8f79 --- /dev/null +++ b/roles/static_inventory/templates/ssh-tunnel.service.j2 @@ -0,0 +1,20 @@ +[Unit] +Description=Set up ssh tunneling for OpenShift cluster UI +After=network.target + +[Service] +ExecStart=/usr/bin/ssh -NT -o \ + ServerAliveInterval=60 -o \ + UserKnownHostsFile=/dev/null -o \ + StrictHostKeyChecking=no -o \ + ExitOnForwardFailure=no -i \ + {{ private_ssh_key }} {{ ssh_user }}@{{ hostvars['bastion'].ansible_host }} \ + -L 0.0.0.0:{{ ui_port }}:{{ target_ip }}:{{ ui_port }} + + +# Restart every >2 seconds to avoid StartLimitInterval failure +RestartSec=5 +Restart=always + +[Install] +WantedBy=multi-user.target |