Skip to content

Commit 55c9de4

Browse files
Merge pull request openshift#7727 from shiftstack/add-support-byon-dualstack-upi
OSASINFRA-3261: OpenStack: support dualstack in UPI
2 parents 5d21725 + 792a0cf commit 55c9de4

File tree

9 files changed

+345
-156
lines changed

9 files changed

+345
-156
lines changed

docs/user/openstack/install_upi.md

Lines changed: 58 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ of this method of installation.
2727
- [OpenShift Configuration Directory](#openshift-configuration-directory)
2828
- [Red Hat Enterprise Linux CoreOS (RHCOS)](#red-hat-enterprise-linux-coreos-rhcos)
2929
- [API and Ingress Floating IP Addresses](#api-and-ingress-floating-ip-addresses)
30+
- [Create network, API and ingress ports](#create-network-api-and-ingress-ports)
3031
- [Install Config](#install-config)
3132
- [Configure the machineNetwork.CIDR apiVIP and ingressVIP](#configure-the-machinenetworkcidr-apivip-and-ingressvip)
3233
- [Empty Compute Pools](#empty-compute-pools)
@@ -44,7 +45,7 @@ of this method of installation.
4445
- [Master Ignition](#master-ignition)
4546
- [Network Topology](#network-topology)
4647
- [Security Groups](#security-groups)
47-
- [Network, Subnet and external router](#network-subnet-and-external-router)
48+
- [Update Network, Subnet, Router and ports](#update-network-subnet-router-and-ports)
4849
- [Subnet DNS (optional)](#subnet-dns-optional)
4950
- [Bootstrap](#bootstrap)
5051
- [Control Plane](#control-plane)
@@ -59,7 +60,7 @@ of this method of installation.
5960

6061
## Prerequisites
6162

62-
The file `inventory.yaml` contains the variables most likely to need customization.
63+
The `inventory.yaml` file contains variables which should be reviewed and adjusted if needed.
6364

6465
> **Note**
6566
> Some of the default pods (e.g. the `openshift-router`) require at least two nodes so that is the effective minimum.
@@ -149,7 +150,7 @@ Make sure that `python` points to Python3:
149150
sudo alternatives --set python /usr/bin/python3
150151
```
151152

152-
To avoid packages not found or mismatchs, we use pip to install the dependencies:
153+
To avoid packages not found or mismatches, we use pip to install the dependencies:
153154
```sh
154155
python3 -m pip install --upgrade pip
155156
python3 -m pip install yq openstackclient openstacksdk netaddr
@@ -227,7 +228,7 @@ access between OpenStack KVM hypervisors and the cluster nodes.
227228
To enable this feature, you must add the `hw_qemu_guest_agent=yes` property to the image:
228229

229230
```
230-
$ openstack image "rhcos-${CLUSTER_NAME}" set --property hw_qemu_guest_agent=yes
231+
$ openstack image set --property hw_qemu_guest_agent=yes "rhcos-${CLUSTER_NAME}"
231232
```
232233

233234
Finally validate that the image was successfully created:
@@ -269,6 +270,19 @@ api.openshift.example.com. A 203.0.113.23
269270

270271
They will need to be available to your developers, end users as well as the OpenShift installer process later in this guide.
271272

273+
## Create network, API and ingress ports
274+
275+
Please note that value of the API and Ingress VIPs fields will be overwritten in the `inventory.yaml` with the respective addresses assigned to the Ports. Run the following playbook to create necessary resources:
276+
277+
<!--- e2e-openstack-upi: INCLUDE START --->
278+
```sh
279+
$ ansible-playbook -i inventory.yaml network.yaml
280+
```
281+
<!--- e2e-openstack-upi: INCLUDE END --->
282+
283+
> **Note**
284+
> These OpenStack resources will be deleted by the `down-network.yaml` playbook.
285+
272286
## Install Config
273287

274288
Run the `create install-config` subcommand and fill in the desired entries:
@@ -304,76 +318,51 @@ $ tree
304318
```
305319

306320
### Configure the machineNetwork.CIDR apiVIP and ingressVIP
321+
307322
The `machineNetwork` represents the OpenStack network which will be used to connect all the OpenShift cluster nodes.
308323
The `machineNetwork.CIDR` defines the IP range, in CIDR notation, from which the installer will choose what IP addresses
309-
to assign the nodes. The `apiVIP` and `ingressVIP` are the IP addresses the installer will assign to the cluster API and
324+
to assign the nodes. The `apiVIPs` and `ingressVIPs` are the IP addresses the installer will assign to the cluster API and
310325
ingress VIPs, respectively.
311-
In the previous steps, the installer added default values for the `machineNetwork.CIDR`, and then it picked the
312-
5th and 7th IP addresses from that range to assign to `apiVIP` and `ingressVIP`.
313-
`machineNetwork.CIDR` needs to match the IP range specified by `os_subnet_range` in the `inventory.yaml` file.
314-
315-
When the installer creates the manifest files from an existing `install-config.yaml` file, it validates that the
316-
`apiVIP` and `ingressVIP` fall within the IP range specified by `machineNetwork.CIDR`. If they do not, it errors out.
317-
If you change the value of `machineNetwork.CIDR` you must make sure the `apiVIP` and `ingressVIP` values still fall within
318-
the new range. There are two options for setting the `apiVIP` and `ingressVIP`. If you know the values you want to use,
319-
you can specify them in the `install-config.yaml` file. If you want the installer to pick the 5th and 7th IP addresses in the
320-
new range, you need to remove the `apiVIP` and `ingressVIP` entries from the `install-config.yaml` file.
321326

322-
To illustrate the process, we will use '192.0.2.0/24' as an example. It defines a usable IP range from
323-
192.0.2.1 to 192.0.2.254. There are some IP addresses that should be avoided because they are usually taken up or
324-
reserved. For example, the first address (.1) is usually assigned to a router. The DHCP and DNS servers will use a few
325-
more addresses, usually .2, .3, .11 and .12. The actual addresses used by these services depend on the configuration of
326-
the OpenStack deployment in use. You should check your OpenStack deployment.
327+
In the previous step, ansible playbook added default values for the
328+
`machineNetwork.CIDR`, and then it assigned selected by Neutron IP addresses for
329+
`apiVIPs` and `ingressVIPs` to appropriate fields inventory file - os_ingressVIP
330+
and os_apiVIP for single stack installation, and additionally os_ingressVIP6 and
331+
os_apiVIP6 for dualstack out of `machineNetwork.CIDR`.
327332

333+
Following script will fill into `intall-config.yaml` the value for `machineNetwork`, `apiVIPs`, `ingressVIPs`, `controlPlanePort`
334+
for single-stack and dual-stack and `networkType`, `clusterNetwork` and `serviceNetwork` only for dual-stack, using `inventory.yaml`
335+
values:
328336

329-
The following script modifies the value of `machineNetwork.CIDR` in the `install-config.yaml` file to match the `os_subnet_range` defined in `inventory.yaml`.
330337
<!--- e2e-openstack-upi: INCLUDE START --->
331338
```sh
332339
$ python -c 'import yaml
333-
installconfig_path = "install-config.yaml"
334-
installconfig = yaml.safe_load(open(installconfig_path))
335-
inventory = yaml.safe_load(open("inventory.yaml"))
336-
inventory_subnet_range = inventory["all"]["hosts"]["localhost"]["os_subnet_range"]
337-
installconfig["networking"]["machineNetwork"][0]["cidr"] = inventory_subnet_range
338-
open(installconfig_path, "w").write(yaml.dump(installconfig, default_flow_style=False))'
339-
```
340-
<!--- e2e-openstack-upi: INCLUDE END --->
341-
342-
Next, we need to correct the `apiVIP` and `ingressVIP` values.
343-
344-
The following script will clear the values from the `install-config.yaml` file so that the installer will pick
345-
the 5th and 7th IP addresses in the new range, 192.0.2.5 and 192.0.2.7.
346-
<!--- e2e-openstack-upi: INCLUDE START --->
347-
```sh
348-
$ python -c 'import yaml
349-
import sys
350340
path = "install-config.yaml"
351341
data = yaml.safe_load(open(path))
352-
if "apiVIP" in data["platform"]["openstack"]:
353-
del data["platform"]["openstack"]["apiVIP"]
354-
if "ingressVIP" in data["platform"]["openstack"]:
355-
del data["platform"]["openstack"]["ingressVIP"]
342+
inventory = yaml.safe_load(open("inventory.yaml"))["all"]["hosts"]["localhost"]
343+
machine_net = [{"cidr": inventory["os_subnet_range"]}]
344+
api_vips = [inventory["os_apiVIP"]]
345+
ingress_vips = [inventory["os_ingressVIP"]]
346+
ctrl_plane_port = {"network": {"name": inventory["os_network"]}, "fixedIPs": [{"subnet": {"name": inventory["os_subnet"]}}]}
347+
if inventory.get("os_subnet6"):
348+
machine_net.append({"cidr": inventory["os_subnet6_range"]})
349+
api_vips.append(inventory["os_apiVIP6"])
350+
ingress_vips.append(inventory["os_ingressVIP6"])
351+
data["networking"]["networkType"] = "OVNKubernetes"
352+
data["networking"]["clusterNetwork"].append({"cidr": inventory["cluster_network6_cidr"], "hostPrefix": inventory["cluster_network6_prefix"]})
353+
data["networking"]["serviceNetwork"].append(inventory["service_subnet6_range"])
354+
ctrl_plane_port["fixedIPs"].append({"subnet": {"name": inventory["os_subnet6"]}})
355+
data["networking"]["machineNetwork"] = machine_net
356+
data["platform"]["openstack"]["apiVIPs"] = api_vips
357+
data["platform"]["openstack"]["ingressVIPs"] = ingress_vips
358+
data["platform"]["openstack"]["controlPlanePort"] = ctrl_plane_port
359+
del data["platform"]["openstack"]["externalDNS"]
356360
open(path, "w").write(yaml.dump(data, default_flow_style=False))'
357361
```
358362
<!--- e2e-openstack-upi: INCLUDE END --->
359363

360-
If you want to specify the values yourself, you can use the following script, which sets them to 192.0.2.8
361-
and 192.0.2.9.
362-
363-
```sh
364-
$ python -c 'import yaml
365-
import sys
366-
path = "install-config.yaml"
367-
data = yaml.safe_load(open(path))
368-
if "apiVIP" in data["platform"]["openstack"]:
369-
data["platform"]["openstack"]["apiVIP"] = "192.0.2.8"
370-
if "ingressVIP" in data["platform"]["openstack"]:
371-
data["platform"]["openstack"]["ingressVIP"] = "192.0.2.9"
372-
open(path, "w").write(yaml.dump(data, default_flow_style=False))'
373-
```
374-
375364
> **Note**
376-
> All the scripts in this guide work with Python 3 as well as Python 2.
365+
> All the scripts in this guide work only with Python 3.
377366
> You can also choose to edit the `install-config.yaml` file by hand.
378367
379368
### Empty Compute Pools
@@ -398,7 +387,7 @@ open(path, "w").write(yaml.dump(data, default_flow_style=False))'
398387

399388
By default the `networkType` is set to `OVNKubernetes` on the `install-config.yaml`.
400389

401-
If an installation with OpenShift SDN is desired, you must modify the `networkType` field.
390+
If an installation with OpenShift SDN is desired, you must modify the `networkType` field. Note, that dual-stack only supports `OVNKubernetes` network type.
402391

403392
This command will do it for you:
404393

@@ -689,12 +678,12 @@ Create a file called `$INFRA_ID-bootstrap-ignition.json` (fill in your `infraID`
689678
"config": {
690679
"merge": [
691680
{
692-
"httpHeaders": [
693-
{
694-
"name": "X-Auth-Token",
695-
"value": "${GLANCE_TOKEN}"
696-
}
697-
],
681+
"httpHeaders": [
682+
{
683+
"name": "X-Auth-Token",
684+
"value": "${GLANCE_TOKEN}"
685+
}
686+
],
698687
"source": "${BOOTSTRAP_URL}"
699688
}
700689
]
@@ -755,7 +744,7 @@ else:
755744

756745
infra_id = os.environ.get('INFRA_ID', 'openshift')
757746

758-
bootstrap_ignition_shim = infra_id+'-bootstrap-ignition.json'
747+
bootstrap_ignition_shim = infra_id + '-bootstrap-ignition.json'
759748

760749
with open(bootstrap_ignition_shim, 'r') as f:
761750
ignition_data = json.load(f)
@@ -821,18 +810,14 @@ $ ansible-playbook -i inventory.yaml security-groups.yaml
821810
<!--- e2e-openstack-upi: INCLUDE END --->
822811

823812
The playbook creates one Security group for the Control Plane and one for the Compute nodes, then attaches rules for enabling communication between the nodes.
824-
### Network, Subnet and external router
813+
### Update Network, Subnet, Router and ports
825814
<!--- e2e-openstack-upi: INCLUDE START --->
826815
```sh
827-
$ ansible-playbook -i inventory.yaml network.yaml
816+
$ ansible-playbook -i inventory.yaml update-network-resources.yaml
828817
```
829818
<!--- e2e-openstack-upi: INCLUDE END --->
830819

831-
The playbook creates a network and a subnet. The subnet obeys `os_subnet_range`; however the first ten IP addresses are removed from the allocation pool. These addresses will be used for the VRRP addresses managed by keepalived for high availability. For more information, read the [networking infrastructure design document][net-infra].
832-
833-
Outside connectivity will be provided by attaching the floating IP addresses (IPs in the inventory) to the corresponding routers.
834-
835-
[net-infra]: https://github.com/openshift/installer/blob/master/docs/design/openstack/networking-infrastructure.md
820+
The playbook sets tags to network, subnets, ports and router. It also attaches the floating IP to the API and Ingress ports and set the security group on those ports.
836821

837822
### Subnet DNS (optional)
838823

upi/openstack/bootstrap.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@
1919
- "{{ os_sg_master }}"
2020
allowed_address_pairs:
2121
- ip_address: "{{ os_apiVIP }}"
22+
when: os_subnet6 is not defined
23+
24+
- name: 'Create the bootstrap dualstack server port'
25+
os_port:
26+
name: "{{ os_port_bootstrap }}"
27+
network: "{{ os_network }}"
28+
security_groups:
29+
- "{{ os_sg_master }}"
30+
allowed_address_pairs:
31+
- ip_address: "{{ os_apiVIP }}"
32+
- ip_address: "{{ os_apiVIP6 }}"
33+
when: os_subnet6 is defined
2234

2335
- name: 'Set bootstrap port tag'
2436
command:

upi/openstack/common.yaml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,6 @@
1010
cluster_id_tag: "openshiftClusterID={{ infraID }}"
1111
primary_cluster_network_tag: "{{ infraID }}-primaryClusterNetwork"
1212
os_infra_id: "{{ infraID }}"
13-
os_network: "{{ infraID }}-network"
14-
os_subnet: "{{ infraID }}-nodes"
15-
os_router: "{{ infraID }}-external-router"
16-
# Port names
17-
os_port_api: "{{ infraID }}-api-port"
18-
os_port_ingress: "{{ infraID }}-ingress-port"
1913
os_port_bootstrap: "{{ infraID }}-bootstrap-port"
2014
os_port_master: "{{ infraID }}-master-port"
2115
os_port_worker: "{{ infraID }}-worker-port"

upi/openstack/compute-nodes.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,20 @@
2121
- ip_address: "{{ os_ingressVIP }}"
2222
with_indexed_items: "{{ [os_port_worker] * os_compute_nodes_number }}"
2323
register: ports
24+
when: os_subnet6 is not defined
25+
26+
- name: 'Create the dualstack Compute ports'
27+
openstack.cloud.port:
28+
name: "{{ item.1 }}-{{ item.0 }}"
29+
network: "{{ os_network }}"
30+
security_groups:
31+
- "{{ os_sg_worker }}"
32+
allowed_address_pairs:
33+
- ip_address: "{{ os_ingressVIP }}"
34+
- ip_address: "{{ os_ingressVIP6 }}"
35+
with_indexed_items: "{{ [os_port_worker] * os_compute_nodes_number }}"
36+
register: ports
37+
when: os_subnet6 is defined
2438

2539
- name: 'Set Compute ports tag'
2640
ansible.builtin.command:

upi/openstack/control-plane.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,22 @@
2222
- ip_address: "{{ os_ingressVIP }}"
2323
with_indexed_items: "{{ [os_port_master] * os_cp_nodes_number }}"
2424
register: ports
25+
when: os_subnet6 is not defined
26+
27+
- name: 'Create the dualstack Control Plane ports'
28+
openstack.cloud.port:
29+
name: "{{ item.1 }}-{{ item.0 }}"
30+
network: "{{ os_network }}"
31+
security_groups:
32+
- "{{ os_sg_master }}"
33+
allowed_address_pairs:
34+
- ip_address: "{{ os_apiVIP }}"
35+
- ip_address: "{{ os_apiVIP6 }}"
36+
- ip_address: "{{ os_ingressVIP }}"
37+
- ip_address: "{{ os_ingressVIP6 }}"
38+
with_indexed_items: "{{ [os_port_master] * os_cp_nodes_number }}"
39+
register: ports
40+
when: os_subnet6 is defined
2541

2642
- name: 'Set Control Plane ports tag'
2743
ansible.builtin.command:

upi/openstack/inventory.yaml

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,15 @@ all:
44
ansible_connection: local
55
ansible_python_interpreter: "{{ansible_playbook_python}}"
66

7+
# Network resource names
8+
os_network: ocp-network
9+
os_port_api: ocp-api-port
10+
os_port_ingress: ocp-ingress-port
11+
os_router: ocp-external-router
12+
os_subnet: ocp-subnet-v4
13+
714
# User-provided values
815
os_subnet_range: '10.0.0.0/16'
9-
# uncomment for dual stack
10-
# os_subnet6_range: 'd2e:6f44:5dd8:c956::/64'
1116
os_flavor_master: 'm1.xlarge'
1217
os_flavor_worker: 'm1.large'
1318
os_image_rhcos: 'rhcos'
@@ -52,15 +57,43 @@ all:
5257
# in case of install failure.
5358
os_bootstrap_fip: '203.0.113.20'
5459

55-
# An IP address that will be assigned to the API VIP.
60+
# An IPv4 address that will be assigned to the API VIP.
5661
# Be aware that the 10 and 11 of the machineNetwork will
5762
# be taken by neutron dhcp by default, and wont be available.
63+
# This value will be overwritten by the network.yaml playbook.
5864
os_apiVIP: "{{ os_subnet_range | ansible.utils.next_nth_usable(5) }}"
5965

60-
# An IP address that will be assigned to the ingress VIP.
66+
# An IPv4 address that will be assigned to the ingress VIP.
6167
# Be aware that the 10 and 11 of the machineNetwork will
6268
# be taken by neutron dhcp by default, and wont be available.
69+
# This value will be overwritten by the network.yaml playbook.
6370
os_ingressVIP: "{{ os_subnet_range | ansible.utils.next_nth_usable(7) }}"
6471

65-
# Set control-plane nodes to schedule workloads when number of compute nodes is zero
72+
# Set control-plane nodes to schedule workloads when number of compute
73+
# nodes is zero
6674
os_master_schedulable: "{{ os_compute_nodes_number | int == 0 }}"
75+
76+
# Name of the IPv6 subnet. Uncomment to enable dual-stack support
77+
#os_subnet6: ocp-subnet-v6
78+
79+
# IPv6 subnet CIDR
80+
os_subnet6_range: 'fd2e:6f44:5dd8:c956::/64'
81+
82+
# Modes are one of: slaac, dhcpv6-stateful or dhcpv6-stateless
83+
os_subnet6_address_mode: slaac
84+
os_subnet6_router_advertisements_mode: slaac
85+
86+
# IPv6 service subnet cidr
87+
service_subnet6_range: 'fd02::/112'
88+
89+
# IPv6 cluster network details
90+
cluster_network6_cidr: 'fd01::/48'
91+
cluster_network6_prefix: 64
92+
93+
# An IPv6 address that will be assigned to the API VIP.
94+
# This value will be overwritten by the network.yaml playbook.
95+
os_apiVIP6: ""
96+
97+
# An IPv6 address that will be assigned to the ingress VIP.
98+
# This value will be overwritten by the network.yaml playbook.
99+
os_ingressVIP6: ""

0 commit comments

Comments
 (0)