├── validate ├── stop.sh ├── run.sh ├── start.sh ├── validate.sh └── do.tf ├── .gitignore ├── user-custom-exports.sh ├── vol.yaml ├── inventory.ini ├── README.md └── install-openshift.sh /validate/stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source env.sh 4 | 5 | terraform destroy -auto-approve -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | validate/env.sh 3 | validate/.terraform 4 | validate/terraform.* 5 | validate/ip.tmp 6 | openshift-ansible 7 | -------------------------------------------------------------------------------- /validate/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl https://raw.githubusercontent.com/okd-community-install/installcentos/master/install-openshift.sh | INTERACTIVE=false /bin/bash 4 | -------------------------------------------------------------------------------- /user-custom-exports.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export DOMAIN="" 4 | export USERNAME="" 5 | export PASSWORD="" 6 | export SCRIPT_REPO="" 7 | export IP="" 8 | export DISK="" 9 | -------------------------------------------------------------------------------- /validate/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | source env.sh 4 | 5 | terraform init 6 | 7 | terraform apply -auto-approve 8 | 9 | terraform show 10 | 11 | ssh -t root@`cat ip.tmp` 'tmux attach' -------------------------------------------------------------------------------- /validate/validate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | yum -y update 4 | 5 | yum -y install tmux 6 | 7 | tmux new-session -d -s installcentos 8 | 9 | chmod +x /root/run.sh 10 | 11 | tmux send -t installcentos /root/run.sh ENTER -------------------------------------------------------------------------------- /vol.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolume 3 | metadata: 4 | name: vol 5 | spec: 6 | capacity: 7 | storage: 500Gi 8 | accessModes: 9 | - ReadWriteOnce 10 | - ReadWriteMany 11 | persistentVolumeReclaimPolicy: Retain 12 | hostPath: 13 | path: /mnt/data/vol 14 | -------------------------------------------------------------------------------- /validate/do.tf: -------------------------------------------------------------------------------- 1 | resource "digitalocean_ssh_key" "openshift" { 2 | name = "openshift" 3 | public_key = "${file("~/.ssh/id_rsa.pub")}" 4 | } 5 | 6 | resource "digitalocean_droplet" "openshift" { 7 | image = "centos-7-x64" 8 | name = "openshift" 9 | region = "ams3" 10 | size = "s-6vcpu-16gb" 11 | ssh_keys = ["${digitalocean_ssh_key.openshift.fingerprint}"] 12 | monitoring = true 13 | 14 | provisioner "file" { 15 | source = "validate.sh" 16 | destination = "/root/validate.sh" 17 | } 18 | 19 | provisioner "file" { 20 | source = "run.sh" 21 | destination = "/root/run.sh" 22 | } 23 | 24 | provisioner "remote-exec" { 25 | inline = [ 26 | "chmod +x /root/validate.sh", 27 | "/root/validate.sh", 28 | ] 29 | } 30 | 31 | provisioner "local-exec" { 32 | command = "echo ${digitalocean_droplet.openshift.ipv4_address} > ip.tmp" 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /inventory.ini: -------------------------------------------------------------------------------- 1 | [OSEv3:children] 2 | masters 3 | nodes 4 | etcd 5 | 6 | [masters] 7 | ${IP} openshift_ip=${IP} openshift_schedulable=true 8 | 9 | [etcd] 10 | ${IP} openshift_ip=${IP} 11 | 12 | [nodes] 13 | ${IP} openshift_ip=${IP} openshift_schedulable=true openshift_node_group_name="node-config-all-in-one" 14 | 15 | [OSEv3:vars] 16 | openshift_additional_repos=[{'id': 'centos-paas', 'name': 'centos-paas', 'baseurl' :'https://buildlogs.centos.org/centos/7/paas/x86_64/openshift-origin311', 'gpgcheck' :'0', 'enabled' :'1'}] 17 | 18 | ansible_ssh_user=root 19 | enable_excluders=False 20 | enable_docker_excluder=False 21 | ansible_service_broker_install=False 22 | 23 | containerized=True 24 | os_sdn_network_plugin_name='redhat/openshift-ovs-multitenant' 25 | openshift_disable_check=disk_availability,docker_storage,memory_availability,docker_image_availability 26 | 27 | deployment_type=origin 28 | openshift_deployment_type=origin 29 | 30 | template_service_broker_selector={"region":"infra"} 31 | openshift_metrics_image_version="v${VERSION}" 32 | openshift_logging_image_version="v${VERSION}" 33 | openshift_logging_elasticsearch_proxy_image_version="v1.0.0" 34 | openshift_logging_es_nodeselector={"node-role.kubernetes.io/infra":"true"} 35 | logging_elasticsearch_rollout_override=false 36 | osm_use_cockpit=true 37 | 38 | openshift_metrics_install_metrics=${METRICS} 39 | openshift_logging_install_logging=${LOGGING} 40 | 41 | openshift_master_identity_providers=[{'name': 'htpasswd_auth', 'login': 'true', 'challenge': 'true', 'kind': 'HTPasswdPasswordIdentityProvider'}] 42 | openshift_master_htpasswd_file='/etc/origin/master/htpasswd' 43 | 44 | openshift_public_hostname=console.${DOMAIN} 45 | openshift_master_default_subdomain=apps.${DOMAIN} 46 | openshift_master_api_port=${API_PORT} 47 | openshift_master_console_port=${API_PORT} 48 | 49 | openshift_cockpit_deployer_image="registry.access.redhat.com/openshift3/registry-console:v${VERSION}" 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Note:** Update: November 2019 - I no longer work at Red Hat on the OpenShift team. Given that, I will not be updating this repo to work with OpenShift 4.x on baremetal. My future work will be centered on a more pure upstream kubernetes experience. If a community member wants to add support for 4.x, I will gladly accept a PR. 2 | 3 | Install RedHat OKD 3.11 on your own server. For a local only install, it is suggested that you use CDK or MiniShift instead of this repo. This install method is targeted for a single node cluster that has a long life. 4 | 5 | This repository is a set of scripts that will allow you easily install the latest version (3.11) of OKD in a single node fashion. What that means is that all of the services required for OKD to function (master, node, etcd, etc.) will all be installed on a single host. The script supports a custom hostname which you can provide using the interactive mode. 6 | 7 | **If you are wanting to install OCP on RDO (OpenStack)** 8 | 9 | Michel Peterson has created a wrapper script in his repo that will do all the heavy lifting for you. Check it out! 10 | 11 | https://github.com/mpeterson/rdo-openshift-tools 12 | 13 | 14 | **Please do use a clean CentOS system, the script installs all necesary tools and packages including Ansible, container runtime, etc.** 15 | 16 | > **Warning about Let's Encrypt setup available on this project:** 17 | > Let's Encrypt only works if the IP is using publicly accessible IP and custom certificates." 18 | > This feature doesn't work with OpenShift CLI for now. 19 | 20 | ## Installation 21 | 22 | 1. Create a VM as explained in https://www.youtube.com/watch?v=ZkFIozGY0IA (this video) by Grant Shipley 23 | 24 | 2. Clone this repo 25 | 26 | ``` 27 | git clone https://github.com/okd-community-install/installcentos.git 28 | ``` 29 | 30 | 3. Execute the installation script 31 | 32 | ``` 33 | cd installcentos 34 | ./install-openshift.sh 35 | ``` 36 | 37 | ## Automation 38 | 1. Define mandatory variables for the installation process 39 | 40 | ``` 41 | # Domain name to access the cluster 42 | $ export DOMAIN=.nip.io 43 | 44 | # User created after installation 45 | $ export USERNAME= 46 | 47 | # Password for the user 48 | $ export PASSWORD=password 49 | ``` 50 | 51 | 2. Define optional variables for the installation process 52 | 53 | ``` 54 | # Instead of using loopback, setup DeviceMapper on this disk. 55 | # !! All data on the disk will be wiped out !! 56 | $ export DISK="/dev/sda" 57 | ``` 58 | 59 | 3. Run the automagic installation script as root with the environment variable in place: 60 | 61 | ``` 62 | curl https://raw.githubusercontent.com/okd-community-install/installcentos/master/install-openshift.sh | INTERACTIVE=false /bin/bash 63 | ``` 64 | 65 | ## Development 66 | 67 | For development it's possible to switch the script repo 68 | 69 | ``` 70 | # Change location of source repository 71 | $ export SCRIPT_REPO="https://raw.githubusercontent.com/okd-community-install/installcentos/master" 72 | $ curl $SCRIPT_REPO/install-openshift.sh | /bin/bash 73 | ``` 74 | 75 | ## Testing 76 | 77 | The script is tested using the tooling in the `validate` directory. 78 | 79 | To use the tooling, it's required to create file `validate/env.sh` with the DigitalOcean API key 80 | 81 | ``` 82 | export DIGITALOCEAN_TOKEN="" 83 | ``` 84 | 85 | and then run `start.sh` to start the provisioning. Once the ssh is connected to the server, the 86 | script will atatch to the `tmux` session running Ansible installer. 87 | 88 | To destroy the infrastructure, run the `stop.sh` script. 89 | -------------------------------------------------------------------------------- /install-openshift.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## see: https://youtu.be/aqXSbDZggK4 4 | 5 | ## Default variables to use 6 | export INTERACTIVE=${INTERACTIVE:="true"} 7 | export PVS=${PVS:="true"} 8 | export DOMAIN=${DOMAIN:="$(curl -s ipinfo.io/ip).nip.io"} 9 | export USERNAME=${USERNAME:="$(whoami)"} 10 | export PASSWORD=${PASSWORD:=password} 11 | export VERSION=${VERSION:="3.11"} 12 | export SCRIPT_REPO=${SCRIPT_REPO:="https://raw.githubusercontent.com/okd-community-install/installcentos/master"} 13 | export IP=${IP:="$(ip route get 8.8.8.8 | awk '{print $NF; exit}')"} 14 | export API_PORT=${API_PORT:="8443"} 15 | export LETSENCRYPT=${LETSENCRYPT:="false"} 16 | export CLOUDFLARE=${CLOUDFLARE:="false"} 17 | export CF_MAIL=${CF_MAIL:="example@email.com"} 18 | export CF_KEY=${CF_KEY:="xxxxxx"} 19 | export MAIL=${MAIL:="example@email.com"} 20 | 21 | ## Make the script interactive to set the variables 22 | if [ "$INTERACTIVE" = "true" ]; then 23 | read -rp "Domain to use: ($DOMAIN): " choice; 24 | if [ "$choice" != "" ] ; then 25 | export DOMAIN="$choice"; 26 | fi 27 | 28 | read -rp "Username: ($USERNAME): " choice; 29 | if [ "$choice" != "" ] ; then 30 | export USERNAME="$choice"; 31 | fi 32 | 33 | read -rp "Password: ($PASSWORD): " choice; 34 | if [ "$choice" != "" ] ; then 35 | export PASSWORD="$choice"; 36 | fi 37 | 38 | read -rp "OpenShift Version: ($VERSION): " choice; 39 | if [ "$choice" != "" ] ; then 40 | export VERSION="$choice"; 41 | fi 42 | read -rp "IP: ($IP): " choice; 43 | if [ "$choice" != "" ] ; then 44 | export IP="$choice"; 45 | fi 46 | 47 | read -rp "API Port: ($API_PORT): " choice; 48 | if [ "$choice" != "" ] ; then 49 | export API_PORT="$choice"; 50 | fi 51 | 52 | echo "Do you wish to enable HTTPS with Let's Encrypt?" 53 | echo "Warnings: " 54 | echo " Let's Encrypt only works if the IP is using publicly accessible IP and custom certificates." 55 | echo " This feature doesn't work with OpenShift CLI for now." 56 | select yn in "Yes" "No"; do 57 | case $yn in 58 | Yes) export LETSENCRYPT=true; break;; 59 | No) export LETSENCRYPT=false; break;; 60 | *) echo "Please select Yes or No.";; 61 | esac 62 | done 63 | 64 | if [ "$LETSENCRYPT" = true ] ; then 65 | read -rp "Email(required for Let's Encrypt): ($MAIL): " choice; 66 | if [ "$choice" != "" ] ; then 67 | export MAIL="$choice"; 68 | fi 69 | 70 | echo "Are you using CloudFlare as DNS-Provider?" 71 | select yn in "Yes" "No"; do 72 | case $yn in 73 | Yes) export CLOUDFLARE=true; break;; 74 | No) export CLOUDFLARE=false; break;; 75 | *) echo "Please select Yes or No.";; 76 | esac 77 | done 78 | 79 | if [ "$CLOUDFLARE" = true ] ; then 80 | read -rp "CloudFlare Username (E-Mail): ($CF_MAIL): " choice; 81 | if [ "$choice" != "" ] ; then 82 | export CF_MAIL="$choice"; 83 | fi 84 | 85 | read -rp "CloudFlare Global APi-Key: ($CF_KEY): " choice; 86 | if [ "$choice" != "" ] ; then 87 | export CF_KEY="$choice"; 88 | fi 89 | fi 90 | fi 91 | 92 | echo 93 | 94 | fi 95 | 96 | echo "******" 97 | echo "* Your domain is $DOMAIN " 98 | echo "* Your IP is $IP " 99 | echo "* Your username is $USERNAME " 100 | echo "* Your password is $PASSWORD " 101 | echo "* OpenShift version: $VERSION " 102 | echo "* Enable HTTPS with Let's Encrypt: $LETSENCRYPT " 103 | if [ "$LETSENCRYPT" = true ] ; then 104 | echo "* Your email is $MAIL " 105 | fi 106 | echo "******" 107 | 108 | # install updates 109 | yum update -y 110 | 111 | # install the following base packages 112 | yum install -y wget git zile nano net-tools docker-1.13.1\ 113 | bind-utils iptables-services \ 114 | bridge-utils bash-completion \ 115 | kexec-tools sos psacct openssl-devel \ 116 | httpd-tools NetworkManager \ 117 | python-cryptography python2-pip python-devel python-passlib \ 118 | java-1.8.0-openjdk-headless "@Development Tools" 119 | 120 | #install epel 121 | yum -y install epel-release 122 | 123 | # Disable the EPEL repository globally so that is not accidentally used during later steps of the installation 124 | sed -i -e "s/^enabled=1/enabled=0/" /etc/yum.repos.d/epel.repo 125 | 126 | systemctl | grep "NetworkManager.*running" 127 | if [ $? -eq 1 ]; then 128 | systemctl start NetworkManager 129 | systemctl enable NetworkManager 130 | fi 131 | 132 | # install the packages for Ansible 133 | yum -y --enablerepo=epel install pyOpenSSL 134 | 135 | curl -o ansible.rpm https://releases.ansible.com/ansible/rpm/release/epel-7-x86_64/ansible-2.6.5-1.el7.ans.noarch.rpm 136 | yum -y --enablerepo=epel install ansible.rpm 137 | 138 | [ ! -d openshift-ansible ] && git clone https://github.com/openshift/openshift-ansible.git -b release-${VERSION} --depth=1 139 | 140 | cat < /etc/hosts 141 | 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 142 | ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 143 | ${IP} $(hostname) console console.${DOMAIN} 144 | EOD 145 | 146 | if [ -z $DISK ]; then 147 | echo "Not setting the Docker storage." 148 | else 149 | cp /etc/sysconfig/docker-storage-setup /etc/sysconfig/docker-storage-setup.bk 150 | 151 | echo DEVS=$DISK > /etc/sysconfig/docker-storage-setup 152 | echo VG=DOCKER >> /etc/sysconfig/docker-storage-setup 153 | echo SETUP_LVM_THIN_POOL=yes >> /etc/sysconfig/docker-storage-setup 154 | echo DATA_SIZE="100%FREE" >> /etc/sysconfig/docker-storage-setup 155 | 156 | systemctl stop docker 157 | 158 | rm -rf /var/lib/docker 159 | wipefs --all $DISK 160 | docker-storage-setup 161 | fi 162 | 163 | systemctl restart docker 164 | systemctl enable docker 165 | 166 | if [ ! -f ~/.ssh/id_rsa ]; then 167 | ssh-keygen -q -f ~/.ssh/id_rsa -N "" 168 | cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys 169 | ssh -o StrictHostKeyChecking=no root@$IP "pwd" < /dev/null 170 | fi 171 | 172 | export METRICS="True" 173 | export LOGGING="True" 174 | 175 | memory=$(cat /proc/meminfo | grep MemTotal | sed "s/MemTotal:[ ]*\([0-9]*\) kB/\1/") 176 | 177 | if [ "$memory" -lt "4194304" ]; then 178 | export METRICS="False" 179 | fi 180 | 181 | if [ "$memory" -lt "16777216" ]; then 182 | export LOGGING="False" 183 | fi 184 | 185 | curl -o inventory.download $SCRIPT_REPO/inventory.ini 186 | envsubst < inventory.download > inventory.ini 187 | 188 | # add proxy in inventory.ini if proxy variables are set 189 | if [ ! -z "${HTTPS_PROXY:-${https_proxy:-${HTTP_PROXY:-${http_proxy}}}}" ]; then 190 | echo >> inventory.ini 191 | echo "openshift_http_proxy=\"${HTTP_PROXY:-${http_proxy:-${HTTPS_PROXY:-${https_proxy}}}}\"" >> inventory.ini 192 | echo "openshift_https_proxy=\"${HTTPS_PROXY:-${https_proxy:-${HTTP_PROXY:-${http_proxy}}}}\"" >> inventory.ini 193 | if [ ! -z "${NO_PROXY:-${no_proxy}}" ]; then 194 | __no_proxy="${NO_PROXY:-${no_proxy}},${IP},.${DOMAIN}" 195 | else 196 | __no_proxy="${IP},.${DOMAIN}" 197 | fi 198 | echo "openshift_no_proxy=\"${__no_proxy}\"" >> inventory.ini 199 | fi 200 | 201 | # Let's Encrypt setup 202 | if [ "$LETSENCRYPT" = true ] ; 203 | then 204 | # Install CertBot 205 | yum install --enablerepo=epel -y certbot 206 | 207 | if [ "$CLOUDFLARE" = true ] ; then 208 | yum install -y --enablerepo=epel python2-cloudflare python2-certbot-dns-cloudflare 209 | 210 | mkdir ~/.secrets 211 | mkdir ~/.secrets/certbot 212 | 213 | cat <> ~/.secrets/certbot/cloudflare.ini 214 | 215 | # Cloudflare API credentials used by Certbot 216 | dns_cloudflare_email = ${CF_MAIL} 217 | dns_cloudflare_api_key = ${CF_KEY} 218 | EOT 219 | 220 | chmod 600 ~/.secrets/certbot/cloudflare.ini 221 | 222 | # Configure Let's Encrypt certificate 223 | certbot certonly --dns-cloudflare \ 224 | --server https://acme-v02.api.letsencrypt.org/directory \ 225 | --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \ 226 | --email $MAIL \ 227 | -d $DOMAIN \ 228 | -d *.$DOMAIN \ 229 | -d *.apps.$DOMAIN 230 | 231 | else 232 | # Configure Let's Encrypt certificate 233 | certbot certonly --manual \ 234 | --preferred-challenges dns \ 235 | --email $MAIL \ 236 | --server https://acme-v02.api.letsencrypt.org/directory \ 237 | --agree-tos \ 238 | -d $DOMAIN \ 239 | -d *.$DOMAIN \ 240 | -d *.apps.$DOMAIN 241 | fi 242 | 243 | ## Modify inventory.ini 244 | # Declare usage of Custom Certificate 245 | # Configure Custom Certificates for the Web Console or CLI => Doesn't Work for CLI 246 | # Configure a Custom Master Host Certificate 247 | # Configure a Custom Wildcard Certificate for the Default Router 248 | # Configure a Custom Certificate for the Image Registry 249 | ## See here for more explanation: https://docs.okd.io/latest/install_config/certificate_customization.html 250 | cat <> inventory.ini 251 | 252 | openshift_master_overwrite_named_certificates=true 253 | 254 | openshift_master_cluster_hostname=console-internal.${DOMAIN} 255 | openshift_master_cluster_public_hostname=console.${DOMAIN} 256 | 257 | openshift_master_named_certificates=[{"certfile": "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem", "keyfile": "/etc/letsencrypt/live/${DOMAIN}/privkey.pem", "cafile": "/etc/letsencrypt/live/${DOMAIN}/chain.pem", "names": ["console.${DOMAIN}"]}] 258 | 259 | openshift_hosted_router_certificate={"certfile": "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem", "keyfile": "/etc/letsencrypt/live/${DOMAIN}/privkey.pem", "cafile": "/etc/letsencrypt/live/${DOMAIN}/chain.pem"} 260 | 261 | openshift_hosted_registry_routehost=registry.apps.${DOMAIN} 262 | openshift_hosted_registry_routecertificates={"certfile": "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem", "keyfile": "/etc/letsencrypt/live/${DOMAIN}/privkey.pem", "cafile": "/etc/letsencrypt/live/${DOMAIN}/chain.pem"} 263 | openshift_hosted_registry_routetermination=reencrypt 264 | EOT 265 | 266 | # Add Cron Task to renew certificate 267 | echo "@weekly certbot renew --pre-hook=\"oc scale --replicas=0 dc router\" --post-hook=\"oc scale --replicas=1 dc router\"" > certbotcron 268 | crontab certbotcron 269 | rm certbotcron 270 | fi 271 | 272 | mkdir -p /etc/rhsm/ca 273 | openssl s_client -showcerts -servername registry.access.redhat.com -connect registry.access.redhat.com:443 /dev/null | openssl x509 -text > /etc/rhsm/ca/redhat-uep.pem 274 | 275 | mkdir -p /etc/origin/master/ 276 | touch /etc/origin/master/htpasswd 277 | 278 | ansible-playbook -i inventory.ini openshift-ansible/playbooks/prerequisites.yml 279 | ansible-playbook -i inventory.ini openshift-ansible/playbooks/deploy_cluster.yml 280 | 281 | htpasswd -b /etc/origin/master/htpasswd ${USERNAME} ${PASSWORD} 282 | oc adm policy add-cluster-role-to-user cluster-admin ${USERNAME} 283 | 284 | if [ "$PVS" = "true" ]; then 285 | 286 | curl -o vol.yaml $SCRIPT_REPO/vol.yaml 287 | 288 | for i in `seq 1 200`; 289 | do 290 | DIRNAME="vol$i" 291 | mkdir -p /mnt/data/$DIRNAME 292 | chcon -Rt svirt_sandbox_file_t /mnt/data/$DIRNAME 293 | chmod 777 /mnt/data/$DIRNAME 294 | 295 | sed "s/name: vol/name: vol$i/g" vol.yaml > oc_vol.yaml 296 | sed -i "s/path: \/mnt\/data\/vol/path: \/mnt\/data\/vol$i/g" oc_vol.yaml 297 | oc create -f oc_vol.yaml 298 | echo "created volume $i" 299 | done 300 | rm oc_vol.yaml 301 | fi 302 | 303 | echo "******" 304 | echo "* Your console is https://console.$DOMAIN:$API_PORT" 305 | echo "* Your username is $USERNAME " 306 | echo "* Your password is $PASSWORD " 307 | echo "*" 308 | echo "* Login using:" 309 | echo "*" 310 | echo "$ oc login -u ${USERNAME} -p ${PASSWORD} https://console.$DOMAIN:$API_PORT/" 311 | echo "******" 312 | 313 | oc login -u ${USERNAME} -p ${PASSWORD} https://console.$DOMAIN:$API_PORT/ 314 | --------------------------------------------------------------------------------