├── .gitignore ├── LICENSE ├── README.md ├── ansible.cfg ├── aws ├── main.tf └── variables.tf ├── digitalocean ├── main.tf └── variables.tf ├── modules ├── inventory_generation │ ├── inventory.template.cfg │ ├── inventory.tf │ └── variables.tf ├── openshift_aws │ ├── amis.tf │ ├── ec2_keypair.tf │ ├── main.tf │ ├── nodes.tf │ ├── outputs.tf │ ├── roles.tf │ ├── route53.tf │ ├── security_groups.tf │ ├── variables.tf │ └── vpc.tf └── openshift_digitalocean │ ├── domains.tf │ ├── outputs.tf │ ├── variables.tf │ ├── vms.tf │ └── volumes.tf └── pre-install ├── hostsfile.j2 └── playbook.yml /.gitignore: -------------------------------------------------------------------------------- 1 | # Infrastructure ignores. 2 | .terraform 3 | terraform.tfvars 4 | terraform.tfstate 5 | terraform.tfstate.backup 6 | 7 | # The generated inventory files. 8 | inventory.cfg 9 | preinstall-inventory.cfg 10 | 11 | # Emacs backup files 12 | *~ 13 | 14 | openshift-ansible* 15 | venv 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OpenShift Terraform 2 | 3 | This project sets up an OpenShift Origin cluster (v3.9 currently) on a DigitalOcean infrastructure. The infrastructure creation and generation of inventory files is handled by Terraform. The goal of the project is to eventually add support for various cloud providers. 4 | 5 | 6 | ## Overview 7 | 8 | A lot of this setup is insipred by [Get up and running with OpenShift on AWS](http://www.dwmkerr.com/get-up-and-running-with-openshift-on-aws/). Here's a 10k ft view of how the setup looks like. 9 | 10 | **TODO: add diagram** 11 | 12 | ## Prerequisites 13 | 14 | 1. [Terraform](https://www.terraform.io/intro/getting-started/install.html) Download and install terraform for your OS. 15 | 2. Ansible 16 | 3. A DigitalOcean account with a ReadWrite Token generated. 17 | 18 | ## Creating the Cluster 19 | 20 | ### Provision the infrastructure 21 | 22 | 23 | 24 | ``` 25 | $ export TF_VAR_domain= 26 | $ export DIGITALOCEAN_TOKEN= 27 | $ terraform init 28 | $ terraform apply 29 | ``` 30 | 31 | Generate SSH keypair specific to this cluster. It is called `tf` and `tf.pub` by default. If you call it by a different name, change it in `variables.tf`. 32 | 33 | ``` 34 | $ terraform apply 35 | ``` 36 | 37 | This will generate 2 inventory files, 38 | 39 | `preinstall-inventory.cfg` for installing the prerequisites in the Open Shift cluster. 40 | 41 | `inventory.cfg` needed for the Ansible OpenShift installer. 42 | 43 | ### Install prerequisite software 44 | 45 | ``` 46 | $ ansible-playbook -u root --private-key=~/.ssh/tf -i preinstall-inventory.cfg ./pre-install/playbook.yml 47 | ``` 48 | 49 | ### Install OpenShift cluster on provisioned infrastructure 50 | 51 | Clone the playbook for v3.10. 52 | 53 | ``` 54 | $ git clone git@github.com:openshift/openshift-ansible.git --branch release-3.10 --depth 1 55 | $ cd openshift-ansible 56 | ``` 57 | 58 | Install the verion of Ansible specified in the above repo. To do this, create a virtualenv, and run: 59 | 60 | ``` 61 | $ pip install -r requirements.txt 62 | ``` 63 | 64 | Prerequisite check. 65 | 66 | ``` 67 | $ ansible-playbook -i ../inventory.cfg --private-key=~/.ssh/tf playbooks/prerequisites.yml 68 | ``` 69 | 70 | Provision the cluster. 71 | 72 | ``` 73 | $ ansible-playbook -i ../inventory.cfg --private-key=~/.ssh/tf playbooks/deploy_cluster.yml 74 | ``` 75 | 76 | ### Post install steps 77 | 78 | Login to master node using, 79 | 80 | ``` 81 | $ ssh -i ~/.ssh/tf root@console.example.com 82 | ```` 83 | 84 | And to the nodes using, 85 | 86 | ``` 87 | $ ssh -i ~/.ssh/tf root@node-01.example.com 88 | ``` 89 | 90 | Inside master node, 91 | 92 | Create admin user. 93 | 94 | ``` 95 | $ htpasswd -cb /etc/origin/master/htpasswd admin 96 | ``` 97 | 98 | Set up GlusterFS as the default storageclass. 99 | 100 | ``` 101 | $ kubectl get storageclass 102 | NAME PROVISIONER AGE 103 | glusterfs-storage kubernetes.io/glusterfs 16m 104 | ``` 105 | 106 | ``` 107 | $ oc patch storageclass glusterfs-storage -p '{"metadata":{"annotations":{"storageclass.beta.kubernetes.io/is-default-class":"true"}}}' 108 | ``` 109 | 110 | ### Deploy Drupal s2i image 111 | 112 | Import the image into the openshift registry. 113 | 114 | ``` 115 | $ oc project openshift # all image streams should belong to this namespace 116 | $ oc import-image lakshminp/openshift-drupal:v11 --confirm 117 | ``` 118 | 119 | Add the template either via UI or via cli. 120 | 121 | ## Day 2 stuff 122 | 123 | ### Adding new nodes 124 | 125 | 126 | ## Destroying the Cluster 127 | 128 | ``` 129 | $ terraform destroy 130 | ``` 131 | 132 | ## CI 133 | 134 | ## Contact 135 | 136 | - [email me](mailto:lakshmi@lakshminp.com?subject=Openshift%20Terraform) 137 | - [lakshminp.com](https://www.lakshminp.com) 138 | - [@lakshminp](https://twitter.com/lakshminp) 139 | -------------------------------------------------------------------------------- /ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | host_key_checking = False 3 | 4 | -------------------------------------------------------------------------------- /aws/main.tf: -------------------------------------------------------------------------------- 1 | // Create the infra needed for OpenShift cluster in AWS. 2 | module "openshift_aws" { 3 | source = "../modules/openshift_aws" 4 | 5 | key_name = "openshift" 6 | public_key_path = "${var.public_key_path}" 7 | region = "${var.region}" 8 | master_size = "${var.master_size}" 9 | node_size = "${var.node_size}" 10 | nodes_count = "${var.nodes_count}" 11 | domain = "${var.domain}" 12 | cluster_name = "openshift-cluster" 13 | cluster_id = "trext_in_aws" 14 | } 15 | 16 | 17 | module "inventory_generation" { 18 | source = "../modules/inventory_generation" 19 | 20 | master_domain = "${module.openshift_aws.master_domain}" 21 | node_domains = "${module.openshift_aws.node_domains}" 22 | apps_subdomain = "${module.openshift_aws.apps_subdomain}" 23 | master_ip_address = "${module.openshift_aws.master_ip_address}" 24 | node_ip_address = "${module.openshift_aws.node_ip_address}" 25 | private_key_path = "${var.private_key_path}" 26 | access_key = "${module.openshift_aws.access_key}" 27 | secret_key = "${module.openshift_aws.secret_key}" 28 | ansible_ssh_user = "centos" 29 | use_gluster = false 30 | provider = "aws" 31 | cluster_id = "trext_in_aws" 32 | } 33 | -------------------------------------------------------------------------------- /aws/variables.tf: -------------------------------------------------------------------------------- 1 | variable "key_name" { 2 | default = "openshift" 3 | description = "The name of the key to user for ssh access, e.g: consul-cluster" 4 | } 5 | 6 | variable "public_key_path" { 7 | default = "~/.ssh/tf.pub" 8 | description = "The local public key path, e.g. ~/.ssh/id_rsa.pub" 9 | } 10 | 11 | variable "private_key_path" { 12 | default = "~/.ssh/tf" 13 | description = "The local private key path, e.g. ~/.ssh/id_rsa" 14 | } 15 | 16 | variable "region" { 17 | default = "us-east-1" 18 | description = "The AWS region where the cluster will be spun." 19 | } 20 | 21 | variable "master_size" { 22 | default = "m5.xlarge" 23 | } 24 | 25 | variable "node_size" { 26 | default = "m5.large" 27 | } 28 | 29 | variable "nodes_count" { 30 | default = 1 31 | } 32 | 33 | 34 | variable "domain" { 35 | default = "example.com" 36 | description = "Base domain name for the Openshift cluster." 37 | } 38 | -------------------------------------------------------------------------------- /digitalocean/main.tf: -------------------------------------------------------------------------------- 1 | // Create the infra needed for OpenShift cluster in DO. 2 | 3 | module "openshift_digitalocean" { 4 | source = "../modules/openshift_digitalocean" 5 | 6 | key_name = "openshift" 7 | public_key_path = "${var.public_key_path}" 8 | region = "${var.region}" 9 | master_size = "${var.master_size}" 10 | node_size = "${var.node_size}" 11 | nodes_count = "${var.nodes_count}" 12 | volume_size = "${var.volume_size}" 13 | domain = "${var.domain}" 14 | } 15 | 16 | 17 | module "inventory_generation" { 18 | source = "../modules/inventory_generation" 19 | 20 | master_domain = "${module.openshift_digitalocean.master_domain}", 21 | node_domains = "${module.openshift_digitalocean.node_domains}", 22 | apps_subdomain = "${module.openshift_digitalocean.apps_subdomain}", 23 | master_ip_address = "${module.openshift_digitalocean.master_ip_address}", 24 | node_ip_address = "${module.openshift_digitalocean.node_ip_address}", 25 | private_key_path = "${var.private_key_path}" 26 | use_gluster = true 27 | provider = "digitalocean" 28 | } 29 | -------------------------------------------------------------------------------- /digitalocean/variables.tf: -------------------------------------------------------------------------------- 1 | variable "public_key_path" { 2 | default = "~/.ssh/tf.pub" 3 | description = "The local public key path, e.g. ~/.ssh/id_rsa.pub" 4 | } 5 | 6 | variable "private_key_path" { 7 | default = "~/.ssh/tf" 8 | description = "The local private key path, e.g. ~/.ssh/id_rsa" 9 | } 10 | 11 | variable "region" { 12 | default = "tor1" 13 | description = "The digitalOcean region where the cluster will be spun." 14 | } 15 | 16 | variable "master_size" { 17 | default = "4gb" 18 | description = "Size of the master VM" 19 | } 20 | 21 | variable "node_size" { 22 | default = "4gb" 23 | description = "Size of the Node VMs" 24 | } 25 | 26 | variable "nodes_count" { 27 | default = 2 28 | description = "No. of app nodes to create." 29 | } 30 | 31 | variable "volume_size" { 32 | default = 50 33 | description = "Size of DO volumes in GB" 34 | } 35 | 36 | variable "domain" { 37 | default = "example.com" 38 | description = "Base domain name for the Openshift cluster." 39 | } 40 | -------------------------------------------------------------------------------- /modules/inventory_generation/inventory.template.cfg: -------------------------------------------------------------------------------- 1 | [OSEv3:children] 2 | masters 3 | nodes 4 | etcd 5 | ${gluster_group} 6 | 7 | [masters] 8 | ${master_ips} 9 | 10 | [etcd] 11 | ${etcd_ips} 12 | 13 | [nodes] 14 | ${master_node_entry} 15 | ${nodes} 16 | 17 | 18 | ${glusterfs_master} 19 | ${glusterfs_nodes} 20 | 21 | [OSEv3:vars] 22 | debug_level=4 23 | ansible_ssh_user=${ansible_ssh_user} 24 | enable_excluders=False 25 | enable_docker_excluder=False 26 | openshift_enable_service_catalog=False 27 | ansible_service_broker_install=False 28 | ansible_ssh_private_key=${private_key_path} 29 | 30 | containerized=True 31 | os_sdn_network_plugin_name='redhat/openshift-ovs-multitenant' 32 | openshift_disable_check=disk_availability,docker_storage,memory_availability,docker_image_availability 33 | 34 | openshift_node_kubelet_args={'pods-per-core': ['${pods_per_core}']} 35 | 36 | deployment_type=origin 37 | openshift_deployment_type=origin 38 | 39 | openshift_release=v3.10.0 40 | openshift_image_tag=v3.10.0 41 | openshift_service_catalog_image_version=v3.10.0 42 | template_service_broker_image_version=v3.10.0 43 | 44 | ${aws_keys_block} 45 | 46 | osm_use_cockpit=true 47 | 48 | openshift_clusterid=${cluster_id} 49 | 50 | openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', 'challenge': 'true', 'kind': 'HTPasswdPasswordIdentityProvider'}] 51 | 52 | openshift_public_hostname=${openshift_public_host_name} 53 | openshift_master_default_subdomain=${openshift_master_default_subdomain} 54 | 55 | # Commented out because of https://github.com/openshift/openshift-ansible/issues/9219 56 | #openshift_master_api_port=443 57 | #openshift_master_console_port=443 58 | -------------------------------------------------------------------------------- /modules/inventory_generation/inventory.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | aws_keys_block = <