Compare commits

..

27 Commits

Author SHA1 Message Date
Vincent Link
093d75f04e [2.12] Add 1.16.14 and 1.16.15 support (#6583)
* Use k8s.gcr.io for kubernetes related images (#5764)

* Use k8s.gcr.io for kubernetes related images

* Use k8s.gcr.io in inventory sample

* [2.12] Update hashes and set default version to 1.16.14

* [2.12] Update hashes and set default version to 1.16.15

Co-authored-by: Florent Monbillard <f.monbillard@gmail.com>
2020-09-18 02:10:45 -07:00
Mario Bris
2acc5a75ac fix test if openstack_cacert is a base64 string (#6371) 2020-08-04 01:40:22 -07:00
Florian Ruynat
31526c0b7a [2.12] Update hashes and set default version to 1.16.13 (#6477)
* Move healthz check to secure ports (#6446) (#6457)

* Update hashes and set default version to 1.16.13
2020-08-01 00:27:41 -07:00
Lovro Seder
9a862ae5b3 Fix shellcheck url (#6464) 2020-07-28 23:59:47 -07:00
Florian Ruynat
29cfe2b8eb Update hashes and set default to 1.16.11 (#6287) 2020-06-18 23:45:59 -07:00
Etienne Champetier
b0eecc0bce [2.12] Bump CNI plugins to 0.8.6 (#6227)
https://github.com/containernetworking/plugins/releases/tag/v0.8.6
https://github.com/kubernetes/kubernetes/issues/91507

Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>
(cherry picked from commit 41b44739b1)
2020-06-09 05:23:18 -07:00
Rick Haan
5cba8b1614 Wait for kube-apiserver availability before starting upgrade (#6243)
* Wait for kube-apiserver availability before starting upgrade

I am experiencing a timing issue when upgrading from kubespray
2.11.0(k8s 1.15.3) to kubespray 2.12.6(k8s 1.16.9). The certificates get
replaced in `kubeadm-secondary-legacy.yml` and kube-apiserver notices a mismatch
(for a fraction of a second) between `apiserver.crt` and `apiserver.key`
which causes it to restart. And sometimes ( ~ 1 out of 5 upgrades) the
kube-apiserver isn't back on time for the start of the upgrade task. It
fails when kubeadm checks with the kube-apiserver to start the upgrade. The
kube-apiserver returns a `connect: connection refused`. I have created this
small task to check the availability of the kube-apiserver before starting the
upgrade, so that the upgrade will run without an issue.

Signed-off-by: Rick Haan <rickhaan94@gmail.com>

* Fix markdownlint

* Remove old CI

Co-authored-by: Maxime Guyot <maxime@root314.com>
2020-06-08 07:25:53 -07:00
Florian Ruynat
860bafa62d Update hashes and set default k8s version to 1.16.9 (#6032) 2020-04-28 00:10:04 -07:00
Etienne Champetier
fa35cc02a7 Fix scaling (#5889) (#5911)
* etcd: etcd-events doesn't depend on etcd_cluster_setup

Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>

* etcd: remove condition already present on include_tasks

Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>

* etcd: fix scaling up

Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>

* etcd: use *access_addresses, do not delegate to etcd[0]

We want to wait for the full cluster to be healthy,
so use all the cluster addresses
Also we should be able to run the playbook when etcd[0] is down
(not tested), so do not delegate to etcd[0]

Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>

* etcd: use failed_when for health check

unhealthy cluster is expected on first run, so use failed_when
instead of ignore_errors to remove scary red messages

Also use run_once

Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>

* kubernetes/preinstall: ensure ansible_fqdn is up to date after changing /etc/hosts

Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>

* kubernetes/master: regenerate apiserver cert if needed

Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>
(cherry picked from commit a35b6dc1af)
2020-04-20 00:45:39 -07:00
Maxime Guyot
b4d067e2ed Merge pull request #5930 from Miouge1/release-2.12-lang-dockerfile
[2.12] Set LANG in Dockerfile
2020-04-11 08:48:54 +02:00
Miouge1
7d3f54e940 Set LANG in Dockerfile 2020-04-10 07:02:57 +02:00
Maxime Guyot
51d9e2f9b1 Update to Ansible v2.7.16 (#5850) 2020-03-30 06:21:54 -07:00
chz8494
941aaf93fd remove duplicate ppa step and replace with circtl package download (#5455)
fix error that crictl package not downloaded before install.
```
TASK [container-engine/cri-o : Install crictl] *********************************
fatal: [more-crab]: FAILED! => {"changed": false, "msg": "Source '/tmp/releases/crictl-v1.16.1-linux-amd64.tar.gz' does not exist"}
```
2020-03-30 01:11:53 -07:00
Etienne Champetier
68b3ee8ac1 Add v1.15.10 and v1.15.11 hashes (#5851)
Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>
2020-03-27 23:07:53 -07:00
Etienne Champetier
55da185dfe Add proxy support to containerd, improves no_proxy (#5583) (#5830)
* containerd: add proxy support

Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>

* kubespray-defaults: add kube_service_addresses / kube_pods_subnet to no_proxy

CIDR notation in no_proxy is supported by a lot of programs/languages,
including go: https://github.com/golang/go/issues/16704
Without that containerd cannot talk the the API server (kube_apiserver_ip),
but it should not go through an external proxy for the nodes/pods/services

Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>
(cherry picked from commit 9f2dd09628)
2020-03-27 08:10:23 -07:00
Bort Verwilst
f33aafefa2 added "Flatcar", "Flatcar Container Linux by Kinvolk" for all coreOS role (#5607) (#5818)
Co-authored-by: Sylvain Chateau <sylvain.chateau@epitech.eu>
2020-03-27 06:06:23 -07:00
Maxime Guyot
8f2ad2e2f7 Add moreutils in Dockerfile (#5840) 2020-03-27 06:02:24 -07:00
Etienne Champetier
980ac28d60 kube-proxy need conntrack (#5478) (#5828)
(cherry picked from commit 48c41bcbe7)

Co-authored-by: Damon Wang <wangdekui@inspur.com>
2020-03-26 08:52:26 -07:00
Etienne Champetier
fde234fda7 Fix certificates checking when adding etcd node to existing k8s node (#5807) (#5826)
Co-authored-by: alexkomrakov <alexkomrakov@gmail.com>
(cherry picked from commit 6ad6609872)
2020-03-26 08:50:25 -07:00
Etienne Champetier
de26988e05 containerd: bump to 1.2.13 (#5727) (#5832)
https://github.com/containerd/containerd/releases/tag/v1.2.11
CVE-2019-16884 / CVE-2019-17596

https://github.com/containerd/containerd/releases/tag/v1.2.12
CVE-2019-19921 / CVE-2019-16884 / CVE-2019-11253

https://github.com/containerd/containerd/releases/tag/v1.2.13

Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>
(cherry picked from commit e2ec7c76a4)
2020-03-26 08:48:26 -07:00
Florent Monbillard
173314d9f1 [2.12 branch] Backport Kubernetes 1.16.8 (#5770) (#5774)
* Backport Kubernetes 1.16.8 (#5770)

* Kubernetes 1.16.8

* Upgrade etcd to 3.3.12 (#5718)

* Use kubespray 2.11.2 as start version for the upgrade test case
2020-03-22 23:58:44 -07:00
Kubernetes Prow Robot
e181530333 Backport remove dockerproject (#5682)
* Remove dockerproject org (#5548)

* Change dockerproject.org to download.docker.com

dockerproject.org was deprecated in 2017 and has gone down.

* Restore yum repo for containerd

Change-Id: I883bb512a2164a85865b1bd4fb569af0358c8c2b

Co-authored-by: Craig Rodrigues <rodrigc@crodrigues.org>

* remove legacy docker repo in kubernetes/preinstall before any packages installed (#5640)

* Remove dockerproject_.+_repo_.+ variables (#5662)

This 38688a4486 change replaces the
value for dockerproject_.+_repo_.+ docker variables but their new
value was previously defined in other variables. This change removes
the dockerproject_.+_repo_.+ docker variables in favor of the older
ones.

* Remove stale legacy yum docker repo /etc/yum.repos.d/docker.repo (#5569)

* Remove stale legacy yum docker repo /etc/yum.repos.d/docker.repo

* move task 'Remove legacy docker repo file' to pre-upgrade.yml

* fix upgrade procedure when in playbook (#5695)

exists role kubernetes/preinstall and not exists role container-engine

 error 'yum_repo_dir' is undefined

Co-authored-by: Matthew Mosesohn <matthew.mosesohn@gmail.com>
Co-authored-by: Craig Rodrigues <rodrigc@crodrigues.org>
Co-authored-by: Victor Morales <chipahuac@hotmail.com>
2020-03-05 02:34:38 -08:00
Etienne Champetier
366fb084ef Ensure we always fixup kube-proxy kubeconfig (#5524) (#5558)
When running with serial != 100%, like upgrade_cluster.yml, we need to apply this fixup each time
Problem was introduced in 05dc2b3a09

Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>
(cherry picked from commit 5e9479cded)
2020-02-20 04:15:05 -08:00
Florian Ruynat
34e883e6e2 Upgrade to Kubernetes 1.16.7 (#5627) 2020-02-13 00:36:35 -08:00
Florian Ruynat
22236bfab7 Upgrade to Kubernetes 1.16.6 (#5579) 2020-02-12 02:18:51 -08:00
Kessler
24d28de979 Fix invalid variable in host inventory script (#5482) 2020-01-27 01:59:02 -08:00
Maxime Guyot
86365d61e3 Rebase on 2.12 (#5488) 2020-01-17 02:10:56 -08:00
904 changed files with 10241 additions and 47915 deletions

View File

@@ -2,8 +2,15 @@
parseable: true parseable: true
skip_list: skip_list:
# see https://docs.ansible.com/ansible-lint/rules/default_rules.html for a list of all default rules # see https://docs.ansible.com/ansible-lint/rules/default_rules.html for a list of all default rules
# The following rules throw errors.
# DO NOT add any other rules to this skip_list, instead use local `# noqa` with a comment explaining WHY it is necessary # These either still need to be corrected in the repository and the rules re-enabled or documented why they are skipped on purpose.
- '301'
- '302'
- '303'
- '305'
- '306'
- '404'
- '503'
# These rules are intentionally skipped: # These rules are intentionally skipped:
# #

View File

@@ -1,15 +0,0 @@
root = true
[*.{yaml,yml,yml.j2,yaml.j2}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
charset = utf-8
[{Dockerfile}]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
charset = utf-8

View File

@@ -18,8 +18,6 @@ explain why.
- **Version of Ansible** (`ansible --version`): - **Version of Ansible** (`ansible --version`):
- **Version of Python** (`python --version`):
**Kubespray version (commit) (`git rev-parse --short HEAD`):** **Kubespray version (commit) (`git rev-parse --short HEAD`):**
@@ -27,8 +25,8 @@ explain why.
**Network plugin used**: **Network plugin used**:
**Full inventory with variables (`ansible -i inventory/sample/inventory.ini all -m debug -a "var=hostvars[inventory_hostname]"`):** **Copy of your inventory file:**
<!-- We recommend using snippets services like https://gist.github.com/ etc. -->
**Command used to invoke ansible**: **Command used to invoke ansible**:

View File

@@ -1,7 +1,7 @@
--- ---
name: Support Request name: Support Request
about: Support request or question relating to Kubespray about: Support request or question relating to Kubespray
labels: kind/support labels: triage/support
--- ---

View File

@@ -1,9 +1,9 @@
<!-- Thanks for sending a pull request! Here are some tips for you: <!-- Thanks for sending a pull request! Here are some tips for you:
1. If this is your first time, please read our contributor guidelines: https://git.k8s.io/community/contributors/guide/first-contribution.md and developer guide https://git.k8s.io/community/contributors/devel/development.md 1. If this is your first time, please read our contributor guidelines: https://git.k8s.io/community/contributors/guide#your-first-contribution and developer guide https://git.k8s.io/community/contributors/devel/development.md#development-guide
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request. For reference on required PR/issue labels, read here: 2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request. For reference on required PR/issue labels, read here:
https://git.k8s.io/community/contributors/devel/sig-release/release.md#issuepr-kind-label https://git.k8s.io/community/contributors/devel/release.md#issue-kind-label
3. Ensure you have added or ran the appropriate tests for your PR: https://git.k8s.io/community/contributors/devel/sig-testing/testing.md 3. Ensure you have added or ran the appropriate tests for your PR: https://git.k8s.io/community/contributors/devel/testing.md
4. If you want *faster* PR reviews, read how: https://git.k8s.io/community/contributors/guide/pull-requests.md#best-practices-for-faster-reviews 4. If you want *faster* PR reviews, read how: https://git.k8s.io/community/contributors/guide/pull-requests.md#best-practices-for-faster-reviews
5. Follow the instructions for writing a release note: https://git.k8s.io/community/contributors/guide/release-notes.md 5. Follow the instructions for writing a release note: https://git.k8s.io/community/contributors/guide/release-notes.md
6. If the PR is unfinished, see how to mark it: https://git.k8s.io/community/contributors/guide/pull-requests.md#marking-unfinished-pull-requests 6. If the PR is unfinished, see how to mark it: https://git.k8s.io/community/contributors/guide/pull-requests.md#marking-unfinished-pull-requests

2
.gitignore vendored
View File

@@ -1,7 +1,6 @@
.vagrant .vagrant
*.retry *.retry
**/vagrant_ansible_inventory **/vagrant_ansible_inventory
*.iml
temp temp
.idea .idea
.tox .tox
@@ -15,7 +14,6 @@ contrib/terraform/aws/credentials.tfvars
**/*.sw[pon] **/*.sw[pon]
*~ *~
vagrant/ vagrant/
plugins/mitogen
# Ansible inventory # Ansible inventory
inventory/* inventory/*

View File

@@ -4,18 +4,17 @@ stages:
- deploy-part1 - deploy-part1
- moderator - moderator
- deploy-part2 - deploy-part2
- deploy-part3 - deploy-gce
- deploy-special - deploy-special
variables: variables:
KUBESPRAY_VERSION: v2.14.1
FAILFASTCI_NAMESPACE: 'kargo-ci' FAILFASTCI_NAMESPACE: 'kargo-ci'
GITLAB_REPOSITORY: 'kargo-ci/kubernetes-sigs-kubespray' GITLAB_REPOSITORY: 'kargo-ci/kubernetes-sigs-kubespray'
# DOCKER_HOST: tcp://localhost:2375
ANSIBLE_FORCE_COLOR: "true" ANSIBLE_FORCE_COLOR: "true"
MAGIC: "ci check this" MAGIC: "ci check this"
TEST_ID: "$CI_PIPELINE_ID-$CI_BUILD_ID" TEST_ID: "$CI_PIPELINE_ID-$CI_BUILD_ID"
CI_TEST_VARS: "./tests/files/${CI_JOB_NAME}.yml" CI_TEST_VARS: "./tests/files/${CI_JOB_NAME}.yml"
CI_TEST_REGISTRY_MIRROR: "./tests/common/_docker_hub_registry_mirror.yml"
GS_ACCESS_KEY_ID: $GS_KEY GS_ACCESS_KEY_ID: $GS_KEY
GS_SECRET_ACCESS_KEY: $GS_SECRET GS_SECRET_ACCESS_KEY: $GS_SECRET
CONTAINER_ENGINE: docker CONTAINER_ENGINE: docker
@@ -27,10 +26,7 @@ variables:
IDEMPOT_CHECK: "false" IDEMPOT_CHECK: "false"
RESET_CHECK: "false" RESET_CHECK: "false"
UPGRADE_TEST: "false" UPGRADE_TEST: "false"
MITOGEN_ENABLE: "false" LOG_LEVEL: "-vv"
ANSIBLE_LOG_LEVEL: "-vv"
RECOVER_CONTROL_PLANE_TEST: "false"
RECOVER_CONTROL_PLANE_TEST_GROUPS: "etcd[2:],kube-master[1:]"
before_script: before_script:
- ./tests/scripts/rebase.sh - ./tests/scripts/rebase.sh
@@ -41,14 +37,14 @@ before_script:
.job: &job .job: &job
tags: tags:
- packet - packet
variables:
KUBESPRAY_VERSION: v2.11.2
image: quay.io/kubespray/kubespray:$KUBESPRAY_VERSION image: quay.io/kubespray/kubespray:$KUBESPRAY_VERSION
artifacts:
when: always
paths:
- cluster-dump/
.testcases: &testcases .testcases: &testcases
<<: *job <<: *job
services:
- docker:dind
before_script: before_script:
- update-alternatives --install /usr/bin/python python /usr/bin/python3 1 - update-alternatives --install /usr/bin/python python /usr/bin/python3 1
- ./tests/scripts/rebase.sh - ./tests/scripts/rebase.sh
@@ -56,7 +52,7 @@ before_script:
script: script:
- ./tests/scripts/testcases_run.sh - ./tests/scripts/testcases_run.sh
after_script: after_script:
- chronic ./tests/scripts/testcases_cleanup.sh - ./tests/scripts/testcases_cleanup.sh
# For failfast, at least 1 job must be defined in .gitlab-ci.yml # For failfast, at least 1 job must be defined in .gitlab-ci.yml
# Premoderated with manual actions # Premoderated with manual actions
@@ -74,4 +70,3 @@ include:
- .gitlab-ci/shellcheck.yml - .gitlab-ci/shellcheck.yml
- .gitlab-ci/terraform.yml - .gitlab-ci/terraform.yml
- .gitlab-ci/packet.yml - .gitlab-ci/packet.yml
- .gitlab-ci/vagrant.yml

247
.gitlab-ci/gce.yml Normal file
View File

@@ -0,0 +1,247 @@
---
.gce_variables: &gce_variables
GCE_USER: travis
SSH_USER: $GCE_USER
CLOUD_MACHINE_TYPE: "g1-small"
CI_PLATFORM: "gce"
PRIVATE_KEY: $GCE_PRIVATE_KEY
.cache: &cache
cache:
key: "$CI_BUILD_REF_NAME"
paths:
- downloads/
- $HOME/.cache
.gce: &gce
extends: .testcases
<<: *cache
variables:
<<: *gce_variables
tags:
- gce
except: ['triggers']
only: [/^pr-.*$/]
.centos_weave_kubeadm_variables: &centos_weave_kubeadm_variables
# stage: deploy-part1
UPGRADE_TEST: "graceful"
.centos7_multus_calico_variables: &centos7_multus_calico_variables
# stage: deploy-gce
UPGRADE_TEST: "graceful"
# Builds for PRs only (premoderated by unit-tests step) and triggers (auto)
### PR JOBS PART1
gce_ubuntu18-flannel-aio:
stage: deploy-part1
<<: *gce
when: manual
### PR JOBS PART2
gce_coreos-calico-aio:
stage: deploy-gce
<<: *gce
when: on_success
gce_centos7-flannel-addons:
stage: deploy-gce
<<: *gce
when: manual
### MANUAL JOBS
gce_centos-weave-kubeadm-sep:
stage: deploy-gce
extends: .gce
variables:
<<: *centos_weave_kubeadm_variables
when: on_success
only: ['triggers']
except: []
gce_ubuntu-weave-sep:
stage: deploy-gce
<<: *gce
when: manual
only: ['triggers']
except: []
gce_coreos-calico-sep-triggers:
stage: deploy-gce
<<: *gce
when: on_success
only: ['triggers']
except: []
gce_ubuntu-canal-ha-triggers:
stage: deploy-special
<<: *gce
when: on_success
only: ['triggers']
except: []
gce_centos7-flannel-addons-triggers:
stage: deploy-gce
<<: *gce
when: on_success
only: ['triggers']
except: []
gce_ubuntu-weave-sep-triggers:
stage: deploy-gce
<<: *gce
when: on_success
only: ['triggers']
except: []
# More builds for PRs/merges (manual) and triggers (auto)
gce_ubuntu-canal-ha:
stage: deploy-special
<<: *gce
when: manual
gce_ubuntu-canal-kubeadm:
stage: deploy-gce
<<: *gce
when: manual
gce_ubuntu-canal-kubeadm-triggers:
stage: deploy-gce
<<: *gce
when: on_success
only: ['triggers']
except: []
gce_ubuntu-flannel-ha:
stage: deploy-gce
<<: *gce
when: manual
gce_centos-weave-kubeadm-triggers:
stage: deploy-gce
extends: .gce
variables:
<<: *centos_weave_kubeadm_variables
when: on_success
only: ['triggers']
except: []
gce_ubuntu-contiv-sep:
stage: deploy-special
<<: *gce
when: manual
gce_coreos-cilium:
stage: deploy-special
<<: *gce
when: manual
gce_ubuntu18-cilium-sep:
stage: deploy-special
<<: *gce
when: manual
gce_rhel7-weave:
stage: deploy-gce
<<: *gce
when: manual
gce_rhel7-weave-triggers:
stage: deploy-gce
<<: *gce
when: on_success
only: ['triggers']
except: []
gce_debian9-calico-upgrade:
stage: deploy-gce
<<: *gce
when: manual
gce_debian9-calico-triggers:
stage: deploy-gce
<<: *gce
when: on_success
only: ['triggers']
except: []
gce_coreos-canal:
stage: deploy-gce
<<: *gce
when: manual
gce_coreos-canal-triggers:
stage: deploy-gce
<<: *gce
when: on_success
only: ['triggers']
except: []
gce_rhel7-canal-sep:
stage: deploy-special
<<: *gce
when: manual
gce_rhel7-canal-sep-triggers:
stage: deploy-gce
<<: *gce
when: on_success
only: ['triggers']
except: []
gce_centos7-calico-ha:
stage: deploy-special
<<: *gce
when: manual
gce_centos7-calico-ha-triggers:
stage: deploy-gce
<<: *gce
when: on_success
only: ['triggers']
except: []
gce_centos7-kube-router:
stage: deploy-special
<<: *gce
when: manual
gce_centos7-multus-calico:
stage: deploy-gce
extends: .gce
variables:
<<: *centos7_multus_calico_variables
when: manual
gce_oracle-canal:
stage: deploy-gce
<<: *gce
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_opensuse-canal:
stage: deploy-gce
<<: *gce
when: manual
# no triggers yet https://github.com/kubernetes-incubator/kargo/issues/613
gce_coreos-alpha-weave-ha:
stage: deploy-special
<<: *gce
when: manual
gce_coreos-kube-router:
stage: deploy-special
<<: *gce
when: manual
gce_ubuntu-kube-router-sep:
stage: deploy-special
<<: *gce
when: manual

View File

@@ -2,7 +2,6 @@
yamllint: yamllint:
extends: .job extends: .job
stage: unit-tests stage: unit-tests
tags: [light]
variables: variables:
LANG: C.UTF-8 LANG: C.UTF-8
script: script:
@@ -12,17 +11,15 @@ yamllint:
vagrant-validate: vagrant-validate:
extends: .job extends: .job
stage: unit-tests stage: unit-tests
tags: [light]
variables:
VAGRANT_VERSION: 2.2.10
script: script:
- ./tests/scripts/vagrant-validate.sh - curl -sL https://releases.hashicorp.com/vagrant/2.2.4/vagrant_2.2.4_x86_64.deb -o /tmp/vagrant_2.2.4_x86_64.deb
- dpkg -i /tmp/vagrant_2.2.4_x86_64.deb
- vagrant validate --ignore-provider
except: ['triggers', 'master'] except: ['triggers', 'master']
ansible-lint: ansible-lint:
extends: .job extends: .job
stage: unit-tests stage: unit-tests
tags: [light]
# lint every yml/yaml file that looks like it contains Ansible plays # lint every yml/yaml file that looks like it contains Ansible plays
script: |- script: |-
grep -Rl '^- hosts: \|^ hosts: ' --include \*.yml --include \*.yaml . | xargs -P 4 -n 25 ansible-lint -v grep -Rl '^- hosts: \|^ hosts: ' --include \*.yml --include \*.yaml . | xargs -P 4 -n 25 ansible-lint -v
@@ -31,7 +28,6 @@ ansible-lint:
syntax-check: syntax-check:
extends: .job extends: .job
stage: unit-tests stage: unit-tests
tags: [light]
variables: variables:
ANSIBLE_INVENTORY: inventory/local-tests.cfg ANSIBLE_INVENTORY: inventory/local-tests.cfg
ANSIBLE_REMOTE_USER: root ANSIBLE_REMOTE_USER: root
@@ -47,7 +43,6 @@ syntax-check:
tox-inventory-builder: tox-inventory-builder:
stage: unit-tests stage: unit-tests
tags: [light]
extends: .job extends: .job
before_script: before_script:
- ./tests/scripts/rebase.sh - ./tests/scripts/rebase.sh
@@ -61,16 +56,8 @@ tox-inventory-builder:
markdownlint: markdownlint:
stage: unit-tests stage: unit-tests
tags: [light]
image: node image: node
before_script: before_script:
- npm install -g markdownlint-cli@0.22.0 - npm install -g markdownlint-cli
script: script:
- markdownlint $(find . -name '*.md' | grep -vF './.git') --ignore docs/_sidebar.md --ignore contrib/dind/README.md - markdownlint README.md docs --ignore docs/_sidebar.md
ci-matrix:
stage: unit-tests
tags: [light]
image: python:3
script:
- tests/scripts/md-table/test.sh

View File

@@ -1,234 +1,126 @@
--- ---
.packet: .packet: &packet
extends: .testcases extends: .testcases
variables: variables:
CI_PLATFORM: packet CI_PLATFORM: "packet"
SSH_USER: kubespray SSH_USER: "kubespray"
tags: tags:
- packet - packet
except: [triggers]
# CI template for PRs
.packet_pr:
only: [/^pr-.*$/] only: [/^pr-.*$/]
extends: .packet except: ['triggers']
# CI template for periodic CI jobs
# Enabled when PERIODIC_CI_ENABLED var is set
.packet_periodic:
only:
variables:
- $PERIODIC_CI_ENABLED
allow_failure: true
extends: .packet
packet_ubuntu18-calico-aio: packet_ubuntu18-calico-aio:
stage: deploy-part1 stage: deploy-part1
extends: .packet_pr extends: .packet
when: on_success
# Future AIO job
packet_ubuntu20-calico-aio:
stage: deploy-part1
extends: .packet_pr
when: on_success when: on_success
# ### PR JOBS PART2 # ### PR JOBS PART2
packet_centos7-flannel-containerd-addons-ha: packet_centos7-flannel-addons:
extends: .packet_pr extends: .packet
stage: deploy-part2 stage: deploy-part2
when: on_success when: on_success
variables:
MITOGEN_ENABLE: "true"
packet_centos8-crio:
extends: .packet_pr
stage: deploy-part2
when: on_success
packet_ubuntu18-crio:
extends: .packet_pr
stage: deploy-part2
when: manual
variables:
MITOGEN_ENABLE: "true"
packet_ubuntu16-canal-kubeadm-ha:
stage: deploy-part2
extends: .packet_periodic
when: on_success
packet_ubuntu16-canal-sep:
stage: deploy-special
extends: .packet_pr
when: manual
packet_ubuntu16-flannel-ha:
stage: deploy-part2
extends: .packet_pr
when: manual
packet_ubuntu16-kube-router-sep:
stage: deploy-part2
extends: .packet_pr
when: manual
packet_ubuntu16-kube-router-svc-proxy:
stage: deploy-part2
extends: .packet_pr
when: manual
packet_debian10-cilium-svc-proxy:
stage: deploy-part2
extends: .packet_periodic
when: on_success
packet_debian10-containerd:
stage: deploy-part2
extends: .packet_pr
when: on_success
variables:
MITOGEN_ENABLE: "true"
packet_centos7-calico-ha-once-localhost:
stage: deploy-part2
extends: .packet_pr
when: on_success
variables:
# This will instruct Docker not to start over TLS.
DOCKER_TLS_CERTDIR: ""
services:
- docker:19.03.9-dind
packet_centos8-kube-ovn:
stage: deploy-part2
extends: .packet_periodic
when: on_success
packet_centos8-calico:
stage: deploy-part2
extends: .packet_pr
when: on_success
packet_fedora32-weave:
stage: deploy-part2
extends: .packet_pr
when: on_success
packet_opensuse-canal:
stage: deploy-part2
extends: .packet_periodic
when: on_success
packet_ubuntu18-ovn4nfv:
stage: deploy-part2
extends: .packet_periodic
when: on_success
# ### MANUAL JOBS # ### MANUAL JOBS
packet_ubuntu16-weave-sep: packet_centos-weave-kubeadm-sep:
stage: deploy-part2 stage: deploy-part2
extends: .packet_pr extends: .packet
when: on_success
variables:
UPGRADE_TEST: basic
packet_ubuntu-weave-sep:
stage: deploy-part2
extends: .packet
when: manual when: manual
# # More builds for PRs/merges (manual) and triggers (auto)
packet_ubuntu-canal-ha:
stage: deploy-special
extends: .packet
when: manual
packet_ubuntu-canal-kubeadm:
stage: deploy-part2
extends: .packet
when: on_success
packet_ubuntu-flannel-ha:
stage: deploy-part2
extends: .packet
when: manual
# Contiv does not work in k8s v1.16
# packet_ubuntu-contiv-sep:
# stage: deploy-part2
# extends: .packet
# when: on_success
packet_ubuntu18-cilium-sep: packet_ubuntu18-cilium-sep:
stage: deploy-special stage: deploy-special
extends: .packet_pr extends: .packet
when: manual when: manual
packet_ubuntu18-flannel-containerd-ha: packet_ubuntu18-flannel-containerd:
stage: deploy-part2 stage: deploy-part2
extends: .packet_pr extends: .packet
when: manual when: manual
packet_ubuntu18-flannel-containerd-ha-once: packet_debian9-macvlan-sep:
stage: deploy-part2 stage: deploy-part2
extends: .packet_pr extends: .packet
when: manual when: manual
packet_debian9-macvlan: packet_debian9-calico-upgrade:
stage: deploy-part2 stage: deploy-part2
extends: .packet_pr extends: .packet
when: manual when: on_success
variables:
UPGRADE_TEST: graceful
packet_debian10-containerd:
stage: deploy-part2
extends: .packet
when: on_success
packet_centos7-calico-ha: packet_centos7-calico-ha:
stage: deploy-part2 stage: deploy-part2
extends: .packet_pr extends: .packet
when: manual when: manual
packet_centos7-kube-ovn:
stage: deploy-part2
extends: .packet
when: on_success
packet_centos7-kube-router: packet_centos7-kube-router:
stage: deploy-part2 stage: deploy-part2
extends: .packet_pr extends: .packet
when: manual when: manual
packet_centos7-multus-calico: packet_centos7-multus-calico:
stage: deploy-part2 stage: deploy-part2
extends: .packet_pr extends: .packet
when: manual when: manual
packet_oracle7-canal-ha: packet_opensuse-canal:
stage: deploy-part2 stage: deploy-part2
extends: .packet_pr extends: .packet
when: manual when: manual
packet_fedora33-calico: packet_oracle-7-canal:
stage: deploy-part2 stage: deploy-part2
extends: .packet_periodic extends: .packet
when: on_success when: manual
variables:
MITOGEN_ENABLE: "true" packet_ubuntu-kube-router-sep:
stage: deploy-part2
extends: .packet
when: manual
packet_amazon-linux-2-aio: packet_amazon-linux-2-aio:
stage: deploy-part2 stage: deploy-part2
extends: .packet_pr extends: .packet
when: manual when: manual
packet_fedora32-kube-ovn-containerd:
stage: deploy-part2
extends: .packet_periodic
when: on_success
# ### PR JOBS PART3
# Long jobs (45min+)
packet_centos7-weave-upgrade-ha:
stage: deploy-part3
extends: .packet_periodic
when: on_success
variables:
UPGRADE_TEST: basic
MITOGEN_ENABLE: "false"
packet_debian9-calico-upgrade:
stage: deploy-part3
extends: .packet_pr
when: on_success
variables:
UPGRADE_TEST: graceful
MITOGEN_ENABLE: "false"
packet_debian9-calico-upgrade-once:
stage: deploy-part3
extends: .packet_periodic
when: on_success
variables:
UPGRADE_TEST: graceful
MITOGEN_ENABLE: "false"
packet_ubuntu18-calico-ha-recover:
stage: deploy-part3
extends: .packet_periodic
when: on_success
variables:
RECOVER_CONTROL_PLANE_TEST: "true"
RECOVER_CONTROL_PLANE_TEST_GROUPS: "etcd[2:],kube-master[1:]"
packet_ubuntu18-calico-ha-recover-noquorum:
stage: deploy-part3
extends: .packet_periodic
when: on_success
variables:
RECOVER_CONTROL_PLANE_TEST: "true"
RECOVER_CONTROL_PLANE_TEST_GROUPS: "etcd[1:],kube-master[1:]"

View File

@@ -2,9 +2,8 @@
shellcheck: shellcheck:
extends: .job extends: .job
stage: unit-tests stage: unit-tests
tags: [light]
variables: variables:
SHELLCHECK_VERSION: v0.7.1 SHELLCHECK_VERSION: v0.6.0
before_script: before_script:
- ./tests/scripts/rebase.sh - ./tests/scripts/rebase.sh
- curl --silent --location "https://github.com/koalaman/shellcheck/releases/download/"${SHELLCHECK_VERSION}"/shellcheck-"${SHELLCHECK_VERSION}".linux.x86_64.tar.xz" | tar -xJv - curl --silent --location "https://github.com/koalaman/shellcheck/releases/download/"${SHELLCHECK_VERSION}"/shellcheck-"${SHELLCHECK_VERSION}".linux.x86_64.tar.xz" | tar -xJv
@@ -12,5 +11,5 @@ shellcheck:
- shellcheck --version - shellcheck --version
script: script:
# Run shellcheck for all *.sh except contrib/ # Run shellcheck for all *.sh except contrib/
- find . -name '*.sh' -not -path './contrib/*' -not -path './.git/*' | xargs shellcheck --severity error - find . -name '*.sh' -not -path './contrib/*' | xargs shellcheck --severity error
except: ['triggers', 'master'] except: ['triggers', 'master']

View File

@@ -18,14 +18,10 @@
- echo "$PACKET_PRIVATE_KEY" | base64 -d > ~/.ssh/id_rsa - echo "$PACKET_PRIVATE_KEY" | base64 -d > ~/.ssh/id_rsa
- chmod 400 ~/.ssh/id_rsa - chmod 400 ~/.ssh/id_rsa
- echo "$PACKET_PUBLIC_KEY" | base64 -d > ~/.ssh/id_rsa.pub - echo "$PACKET_PUBLIC_KEY" | base64 -d > ~/.ssh/id_rsa.pub
- mkdir -p group_vars
# Random subnet to avoid routing conflicts
- export TF_VAR_subnet_cidr="10.$(( $RANDOM % 256 )).$(( $RANDOM % 256 )).0/24"
.terraform_validate: .terraform_validate:
extends: .terraform_install extends: .terraform_install
stage: unit-tests stage: unit-tests
tags: [light]
only: ['master', /^pr-.*$/] only: ['master', /^pr-.*$/]
script: script:
- terraform validate -var-file=cluster.tfvars contrib/terraform/$PROVIDER - terraform validate -var-file=cluster.tfvars contrib/terraform/$PROVIDER
@@ -33,14 +29,9 @@
.terraform_apply: .terraform_apply:
extends: .terraform_install extends: .terraform_install
tags: [light] stage: deploy-part2
stage: deploy-part3
when: manual when: manual
only: [/^pr-.*$/] only: [/^pr-.*$/]
artifacts:
when: always
paths:
- cluster-dump/
variables: variables:
ANSIBLE_INVENTORY_UNPARSED_FAILED: "true" ANSIBLE_INVENTORY_UNPARSED_FAILED: "true"
ANSIBLE_INVENTORY: hosts ANSIBLE_INVENTORY: hosts
@@ -51,75 +42,33 @@
- tests/scripts/testcases_run.sh - tests/scripts/testcases_run.sh
after_script: after_script:
# Cleanup regardless of exit code # Cleanup regardless of exit code
- chronic ./tests/scripts/testcases_cleanup.sh - ./tests/scripts/testcases_cleanup.sh
tf-validate-openstack: tf-validate-openstack:
extends: .terraform_validate extends: .terraform_validate
variables: variables:
TF_VERSION: 0.12.29 TF_VERSION: 0.12.12
PROVIDER: openstack PROVIDER: openstack
CLUSTER: $CI_COMMIT_REF_NAME CLUSTER: $CI_COMMIT_REF_NAME
tf-validate-packet: tf-validate-packet:
extends: .terraform_validate extends: .terraform_validate
variables: variables:
TF_VERSION: 0.12.29 TF_VERSION: 0.12.12
PROVIDER: packet PROVIDER: packet
CLUSTER: $CI_COMMIT_REF_NAME CLUSTER: $CI_COMMIT_REF_NAME
tf-validate-aws: tf-validate-aws:
extends: .terraform_validate extends: .terraform_validate
variables: variables:
TF_VERSION: 0.12.29 TF_VERSION: 0.12.12
PROVIDER: aws
CLUSTER: $CI_COMMIT_REF_NAME
tf-0.13.x-validate-openstack:
extends: .terraform_validate
variables:
TF_VERSION: 0.13.5
PROVIDER: openstack
CLUSTER: $CI_COMMIT_REF_NAME
tf-0.13.x-validate-packet:
extends: .terraform_validate
variables:
TF_VERSION: 0.13.5
PROVIDER: packet
CLUSTER: $CI_COMMIT_REF_NAME
tf-0.13.x-validate-aws:
extends: .terraform_validate
variables:
TF_VERSION: 0.13.5
PROVIDER: aws
CLUSTER: $CI_COMMIT_REF_NAME
tf-0.14.x-validate-openstack:
extends: .terraform_validate
variables:
TF_VERSION: 0.14.3
PROVIDER: openstack
CLUSTER: $CI_COMMIT_REF_NAME
tf-0.14.x-validate-packet:
extends: .terraform_validate
variables:
TF_VERSION: 0.14.3
PROVIDER: packet
CLUSTER: $CI_COMMIT_REF_NAME
tf-0.14.x-validate-aws:
extends: .terraform_validate
variables:
TF_VERSION: 0.14.3
PROVIDER: aws PROVIDER: aws
CLUSTER: $CI_COMMIT_REF_NAME CLUSTER: $CI_COMMIT_REF_NAME
# tf-packet-ubuntu16-default: # tf-packet-ubuntu16-default:
# extends: .terraform_apply # extends: .terraform_apply
# variables: # variables:
# TF_VERSION: 0.12.29 # TF_VERSION: 0.12.12
# PROVIDER: packet # PROVIDER: packet
# CLUSTER: $CI_COMMIT_REF_NAME # CLUSTER: $CI_COMMIT_REF_NAME
# TF_VAR_number_of_k8s_masters: "1" # TF_VAR_number_of_k8s_masters: "1"
@@ -133,7 +82,7 @@ tf-0.14.x-validate-aws:
# tf-packet-ubuntu18-default: # tf-packet-ubuntu18-default:
# extends: .terraform_apply # extends: .terraform_apply
# variables: # variables:
# TF_VERSION: 0.12.29 # TF_VERSION: 0.12.12
# PROVIDER: packet # PROVIDER: packet
# CLUSTER: $CI_COMMIT_REF_NAME # CLUSTER: $CI_COMMIT_REF_NAME
# TF_VAR_number_of_k8s_masters: "1" # TF_VAR_number_of_k8s_masters: "1"
@@ -143,117 +92,3 @@ tf-0.14.x-validate-aws:
# TF_VAR_facility: ams1 # TF_VAR_facility: ams1
# TF_VAR_public_key_path: "" # TF_VAR_public_key_path: ""
# TF_VAR_operating_system: ubuntu_18_04 # TF_VAR_operating_system: ubuntu_18_04
.ovh_variables: &ovh_variables
OS_AUTH_URL: https://auth.cloud.ovh.net/v3
OS_PROJECT_ID: 8d3cd5d737d74227ace462dee0b903fe
OS_PROJECT_NAME: "9361447987648822"
OS_USER_DOMAIN_NAME: Default
OS_PROJECT_DOMAIN_ID: default
OS_USERNAME: 8XuhBMfkKVrk
OS_REGION_NAME: UK1
OS_INTERFACE: public
OS_IDENTITY_API_VERSION: "3"
# Elastx is generously donating resources for Kubespray on Openstack CI
# Contacts: @gix @bl0m1
.elastx_variables: &elastx_variables
OS_AUTH_URL: https://ops.elastx.cloud:5000
OS_PROJECT_ID: 564c6b461c6b44b1bb19cdb9c2d928e4
OS_PROJECT_NAME: kubespray_ci
OS_USER_DOMAIN_NAME: Default
OS_PROJECT_DOMAIN_ID: default
OS_USERNAME: kubespray@root314.com
OS_REGION_NAME: se-sto
OS_INTERFACE: public
OS_IDENTITY_API_VERSION: "3"
TF_VAR_router_id: "ab95917c-41fb-4881-b507-3a6dfe9403df"
# Since ELASTX is in Stockholm, Mitogen helps with latency
MITOGEN_ENABLE: "false"
# Mitogen doesn't support interpreter discovery yet
ANSIBLE_PYTHON_INTERPRETER: "/usr/bin/python3"
tf-elastx_cleanup:
stage: unit-tests
tags: [light]
image: python
variables:
<<: *elastx_variables
before_script:
- pip install -r scripts/openstack-cleanup/requirements.txt
script:
- ./scripts/openstack-cleanup/main.py
tf-elastx_ubuntu18-calico:
extends: .terraform_apply
stage: deploy-part3
when: on_success
variables:
<<: *elastx_variables
TF_VERSION: 0.12.29
PROVIDER: openstack
CLUSTER: $CI_COMMIT_REF_NAME
ANSIBLE_TIMEOUT: "60"
SSH_USER: ubuntu
TF_VAR_number_of_k8s_masters: "1"
TF_VAR_number_of_k8s_masters_no_floating_ip: "0"
TF_VAR_number_of_k8s_masters_no_floating_ip_no_etcd: "0"
TF_VAR_number_of_etcd: "0"
TF_VAR_number_of_k8s_nodes: "1"
TF_VAR_number_of_k8s_nodes_no_floating_ip: "0"
TF_VAR_number_of_gfs_nodes_no_floating_ip: "0"
TF_VAR_number_of_bastions: "0"
TF_VAR_number_of_k8s_masters_no_etcd: "0"
TF_VAR_floatingip_pool: "elx-public1"
TF_VAR_dns_nameservers: '["1.1.1.1", "8.8.8.8", "8.8.4.4"]'
TF_VAR_use_access_ip: "0"
TF_VAR_external_net: "600b8501-78cb-4155-9c9f-23dfcba88828"
TF_VAR_network_name: "ci-$CI_JOB_ID"
TF_VAR_az_list: '["sto1"]'
TF_VAR_az_list_node: '["sto1"]'
TF_VAR_flavor_k8s_master: 3f73fc93-ec61-4808-88df-2580d94c1a9b # v1-standard-2
TF_VAR_flavor_k8s_node: 3f73fc93-ec61-4808-88df-2580d94c1a9b # v1-standard-2
TF_VAR_image: ubuntu-18.04-server-latest
TF_VAR_k8s_allowed_remote_ips: '["0.0.0.0/0"]'
tf-ovh_cleanup:
stage: unit-tests
tags: [light]
image: python
environment: ovh
variables:
<<: *ovh_variables
before_script:
- pip install -r scripts/openstack-cleanup/requirements.txt
script:
- ./scripts/openstack-cleanup/main.py
tf-ovh_ubuntu18-calico:
extends: .terraform_apply
when: on_success
environment: ovh
variables:
<<: *ovh_variables
TF_VERSION: 0.12.29
PROVIDER: openstack
CLUSTER: $CI_COMMIT_REF_NAME
ANSIBLE_TIMEOUT: "60"
SSH_USER: ubuntu
TF_VAR_number_of_k8s_masters: "0"
TF_VAR_number_of_k8s_masters_no_floating_ip: "1"
TF_VAR_number_of_k8s_masters_no_floating_ip_no_etcd: "0"
TF_VAR_number_of_etcd: "0"
TF_VAR_number_of_k8s_nodes: "0"
TF_VAR_number_of_k8s_nodes_no_floating_ip: "1"
TF_VAR_number_of_gfs_nodes_no_floating_ip: "0"
TF_VAR_number_of_bastions: "0"
TF_VAR_number_of_k8s_masters_no_etcd: "0"
TF_VAR_use_neutron: "0"
TF_VAR_floatingip_pool: "Ext-Net"
TF_VAR_external_net: "6011fbc9-4cbf-46a4-8452-6890a340b60b"
TF_VAR_network_name: "Ext-Net"
TF_VAR_flavor_k8s_master: "defa64c3-bd46-43b4-858a-d93bbae0a229" # s1-8
TF_VAR_flavor_k8s_node: "defa64c3-bd46-43b4-858a-d93bbae0a229" # s1-8
TF_VAR_image: "Ubuntu 18.04"
TF_VAR_k8s_allowed_remote_ips: '["0.0.0.0/0"]'

View File

@@ -1,54 +0,0 @@
---
molecule_tests:
tags: [c3.small.x86]
only: [/^pr-.*$/]
except: ['triggers']
image: quay.io/kubespray/vagrant:$KUBESPRAY_VERSION
services: []
stage: deploy-part1
before_script:
- tests/scripts/rebase.sh
- apt-get update && apt-get install -y python3-pip
- update-alternatives --install /usr/bin/python python /usr/bin/python3 10
- python -m pip install -r tests/requirements.txt
- ./tests/scripts/vagrant_clean.sh
script:
- ./tests/scripts/molecule_run.sh
.vagrant:
extends: .testcases
variables:
CI_PLATFORM: "vagrant"
SSH_USER: "vagrant"
VAGRANT_DEFAULT_PROVIDER: "libvirt"
KUBESPRAY_VAGRANT_CONFIG: tests/files/${CI_JOB_NAME}.rb
tags: [c3.small.x86]
only: [/^pr-.*$/]
except: ['triggers']
image: quay.io/kubespray/vagrant:$KUBESPRAY_VERSION
services: []
before_script:
- apt-get update && apt-get install -y python3-pip
- update-alternatives --install /usr/bin/python python /usr/bin/python3 10
- python -m pip install -r tests/requirements.txt
- ./tests/scripts/vagrant_clean.sh
script:
- ./tests/scripts/testcases_run.sh
after_script:
- chronic ./tests/scripts/testcases_cleanup.sh
vagrant_ubuntu18-flannel:
stage: deploy-part2
extends: .vagrant
when: on_success
vagrant_ubuntu18-weave-medium:
stage: deploy-part2
extends: .vagrant
when: manual
vagrant_ubuntu20-flannel:
stage: deploy-part2
extends: .vagrant
when: on_success

View File

@@ -1,9 +1,6 @@
--- ---
extends: default extends: default
ignore: |
.git/
rules: rules:
braces: braces:
min-spaces-inside: 0 min-spaces-inside: 0

View File

@@ -2,30 +2,10 @@
## How to become a contributor and submit your own code ## How to become a contributor and submit your own code
### Environment setup
It is recommended to use filter to manage the GitHub email notification, see [examples for setting filters to Kubernetes Github notifications](https://github.com/kubernetes/community/blob/master/communication/best-practices.md#examples-for-setting-filters-to-kubernetes-github-notifications)
To install development dependencies you can use `pip install -r tests/requirements.txt`
#### Linting
Kubespray uses `yamllint` and `ansible-lint`. To run them locally use `yamllint .` and `ansible-lint`
#### Molecule
[molecule](https://github.com/ansible-community/molecule) is designed to help the development and testing of Ansible roles. In Kubespray you can run it all for all roles with `./tests/scripts/molecule_run.sh` or for a specific role (that you are working with) with `molecule test` from the role directory (`cd roles/my-role`).
When developing or debugging a role it can be useful to run `molecule create` and `molecule converge` separately. Then you can use `molecule login` to SSH into the test environment.
#### Vagrant
Vagrant with VirtualBox or libvirt driver helps you to quickly spin test clusters to test things end to end. See [README.md#vagrant](README.md)
### Contributing A Patch ### Contributing A Patch
1. Submit an issue describing your proposed change to the repo in question. 1. Submit an issue describing your proposed change to the repo in question.
2. The [repo owners](OWNERS) will respond to your issue promptly. 2. The [repo owners](OWNERS) will respond to your issue promptly.
3. Fork the desired repo, develop and test your code changes. 3. Fork the desired repo, develop and test your code changes.
4. Sign the CNCF CLA (<https://git.k8s.io/community/CLA.md#the-contributor-license-agreement>) 4. Sign the CNCF CLA (https://git.k8s.io/community/CLA.md#the-contributor-license-agreement)
5. Submit a pull request. 5. Submit a pull request.

View File

@@ -1,7 +1,4 @@
# Use imutable image tags rather than mutable tags (like ubuntu:18.04) FROM ubuntu:18.04
FROM ubuntu:bionic-20200807
ENV KUBE_VERSION=v1.19.9
RUN mkdir /kubespray RUN mkdir /kubespray
WORKDIR /kubespray WORKDIR /kubespray
@@ -9,16 +6,15 @@ RUN apt update -y && \
apt install -y \ apt install -y \
libssl-dev python3-dev sshpass apt-transport-https jq moreutils \ libssl-dev python3-dev sshpass apt-transport-https jq moreutils \
ca-certificates curl gnupg2 software-properties-common python3-pip rsync ca-certificates curl gnupg2 software-properties-common python3-pip rsync
RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - && \ RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - && \
add-apt-repository \ add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \ $(lsb_release -cs) \
stable" \ stable" \
&& apt update -y && apt-get install docker-ce -y && apt update -y && apt-get install docker-ce -y
COPY . . COPY . .
RUN /usr/bin/python3 -m pip install pip -U && /usr/bin/python3 -m pip install -r tests/requirements.txt && python3 -m pip install -r requirements.txt && update-alternatives --install /usr/bin/python python /usr/bin/python3 1 RUN /usr/bin/python3 -m pip install pip -U && /usr/bin/python3 -m pip install -r tests/requirements.txt && python3 -m pip install -r requirements.txt && update-alternatives --install /usr/bin/python python /usr/bin/python3 1
RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.14.4/bin/linux/amd64/kubectl \
RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/amd64/kubectl \
&& chmod a+x kubectl && cp kubectl /usr/local/bin/kubectl && chmod a+x kubectl && cp kubectl /usr/local/bin/kubectl
# Some tools like yamllint need this # Some tools like yamllint need this

View File

@@ -1,5 +1,5 @@
mitogen: mitogen:
ansible-playbook -c local mitogen.yml -vv ansible-playbook -c local mitogen.yaml -vv
clean: clean:
rm -rf dist/ rm -rf dist/
rm *.retry rm *.retry

2
OWNERS
View File

@@ -4,5 +4,3 @@ approvers:
- kubespray-approvers - kubespray-approvers
reviewers: reviewers:
- kubespray-reviewers - kubespray-reviewers
emeritus_approvers:
- kubespray-emeritus_approvers

View File

@@ -1,18 +1,15 @@
aliases: aliases:
kubespray-approvers: kubespray-approvers:
- ant31
- mattymo - mattymo
- atoms
- chadswen - chadswen
- mirwan - mirwan
- miouge1 - miouge1
- woopstar
- luckysb
- floryut
kubespray-reviewers:
- holmsten
- bozzo
- eppo
- oomichi
kubespray-emeritus_approvers:
- riverzhang - riverzhang
- atoms - verwilst
- ant31 - woopstar
kubespray-reviewers:
- jjungnickel
- archifleks
- holmsten

View File

@@ -2,10 +2,10 @@
![Kubernetes Logo](https://raw.githubusercontent.com/kubernetes-sigs/kubespray/master/docs/img/kubernetes-logo.png) ![Kubernetes Logo](https://raw.githubusercontent.com/kubernetes-sigs/kubespray/master/docs/img/kubernetes-logo.png)
If you have questions, check the documentation at [kubespray.io](https://kubespray.io) and join us on the [kubernetes slack](https://kubernetes.slack.com), channel **\#kubespray**. If you have questions, check the [documentation](https://kubespray.io) and join us on the [kubernetes slack](https://kubernetes.slack.com), channel **\#kubespray**.
You can get your invite [here](http://slack.k8s.io/) You can get your invite [here](http://slack.k8s.io/)
- Can be deployed on **[AWS](docs/aws.md), GCE, [Azure](docs/azure.md), [OpenStack](docs/openstack.md), [vSphere](docs/vsphere.md), [Packet](docs/packet.md) (bare metal), Oracle Cloud Infrastructure (Experimental), or Baremetal** - Can be deployed on **AWS, GCE, Azure, OpenStack, vSphere, Packet (bare metal), Oracle Cloud Infrastructure (Experimental), or Baremetal**
- **Highly available** cluster - **Highly available** cluster
- **Composable** (Choice of the network plugin for instance) - **Composable** (Choice of the network plugin for instance)
- Supports most popular **Linux distributions** - Supports most popular **Linux distributions**
@@ -21,14 +21,14 @@ To deploy the cluster you can use :
```ShellSession ```ShellSession
# Install dependencies from ``requirements.txt`` # Install dependencies from ``requirements.txt``
sudo pip3 install -r requirements.txt sudo pip install -r requirements.txt
# Copy ``inventory/sample`` as ``inventory/mycluster`` # Copy ``inventory/sample`` as ``inventory/mycluster``
cp -rfp inventory/sample inventory/mycluster cp -rfp inventory/sample inventory/mycluster
# Update Ansible inventory file with inventory builder # Update Ansible inventory file with inventory builder
declare -a IPS=(10.10.1.3 10.10.1.4 10.10.1.5) declare -a IPS=(10.10.1.3 10.10.1.4 10.10.1.5)
CONFIG_FILE=inventory/mycluster/hosts.yaml python3 contrib/inventory_builder/inventory.py ${IPS[@]} CONFIG_FILE=inventory/mycluster/inventory.ini python3 contrib/inventory_builder/inventory.py ${IPS[@]}
# Review and change parameters under ``inventory/mycluster/group_vars`` # Review and change parameters under ``inventory/mycluster/group_vars``
cat inventory/mycluster/group_vars/all/all.yml cat inventory/mycluster/group_vars/all/all.yml
@@ -38,7 +38,7 @@ cat inventory/mycluster/group_vars/k8s-cluster/k8s-cluster.yml
# The option `--become` is required, as for example writing SSL keys in /etc/, # The option `--become` is required, as for example writing SSL keys in /etc/,
# installing packages and interacting with various systemd daemons. # installing packages and interacting with various systemd daemons.
# Without --become the playbook will fail to run! # Without --become the playbook will fail to run!
ansible-playbook -i inventory/mycluster/hosts.yaml --become --become-user=root cluster.yml ansible-playbook -i inventory/mycluster/inventory.ini --become --become-user=root cluster.yml
``` ```
Note: When Ansible is already installed via system packages on the control machine, other python packages installed via `sudo pip install -r requirements.txt` will go to a different directory tree (e.g. `/usr/local/lib/python2.7/dist-packages` on Ubuntu) from Ansible's (e.g. `/usr/lib/python2.7/dist-packages/ansible` still on Ubuntu). Note: When Ansible is already installed via system packages on the control machine, other python packages installed via `sudo pip install -r requirements.txt` will go to a different directory tree (e.g. `/usr/local/lib/python2.7/dist-packages` on Ubuntu) from Ansible's (e.g. `/usr/lib/python2.7/dist-packages/ansible` still on Ubuntu).
@@ -75,7 +75,6 @@ vagrant up
- [Requirements](#requirements) - [Requirements](#requirements)
- [Kubespray vs ...](docs/comparisons.md) - [Kubespray vs ...](docs/comparisons.md)
- [Getting started](docs/getting-started.md) - [Getting started](docs/getting-started.md)
- [Setting up your first cluster](docs/setting-up-your-first-cluster.md)
- [Ansible inventory and tags](docs/ansible.md) - [Ansible inventory and tags](docs/ansible.md)
- [Integration with existing ansible repo](docs/integration.md) - [Integration with existing ansible repo](docs/integration.md)
- [Deployment data variables](docs/vars.md) - [Deployment data variables](docs/vars.md)
@@ -83,8 +82,7 @@ vagrant up
- [HA mode](docs/ha-mode.md) - [HA mode](docs/ha-mode.md)
- [Network plugins](#network-plugins) - [Network plugins](#network-plugins)
- [Vagrant install](docs/vagrant.md) - [Vagrant install](docs/vagrant.md)
- [Flatcar Container Linux bootstrap](docs/flatcar.md) - [CoreOS bootstrap](docs/coreos.md)
- [Fedora CoreOS bootstrap](docs/fcos.md)
- [Debian Jessie setup](docs/debian.md) - [Debian Jessie setup](docs/debian.md)
- [openSUSE setup](docs/opensuse.md) - [openSUSE setup](docs/opensuse.md)
- [Downloaded artifacts](docs/downloads.md) - [Downloaded artifacts](docs/downloads.md)
@@ -95,59 +93,57 @@ vagrant up
- [vSphere](docs/vsphere.md) - [vSphere](docs/vsphere.md)
- [Packet Host](docs/packet.md) - [Packet Host](docs/packet.md)
- [Large deployments](docs/large-deployments.md) - [Large deployments](docs/large-deployments.md)
- [Adding/replacing a node](docs/nodes.md)
- [Upgrades basics](docs/upgrades.md) - [Upgrades basics](docs/upgrades.md)
- [Air-Gap installation](docs/offline-environment.md)
- [Roadmap](docs/roadmap.md) - [Roadmap](docs/roadmap.md)
## Supported Linux Distributions ## Supported Linux Distributions
- **Flatcar Container Linux by Kinvolk** - **Container Linux by CoreOS**
- **Debian** Buster, Jessie, Stretch, Wheezy - **Debian** Buster, Jessie, Stretch, Wheezy
- **Ubuntu** 16.04, 18.04, 20.04 - **Ubuntu** 16.04, 18.04
- **CentOS/RHEL** 7, 8 (experimental: see [centos 8 notes](docs/centos8.md)) - **CentOS/RHEL** 7
- **Fedora** 32, 33 - **Fedora** 28
- **Fedora CoreOS** (experimental: see [fcos Note](docs/fcos.md)) - **Fedora/CentOS** Atomic
- **openSUSE** Leap 15.x/Tumbleweed - **openSUSE** Leap 42.3/Tumbleweed
- **Oracle Linux** 7, 8 (experimental: [centos 8 notes](docs/centos8.md) apply) - **Oracle Linux** 7
Note: Upstart/SysV init based OS types are not supported. Note: Upstart/SysV init based OS types are not supported.
## Supported Components ## Supported Components
- Core - Core
- [kubernetes](https://github.com/kubernetes/kubernetes) v1.19.9 - [kubernetes](https://github.com/kubernetes/kubernetes) v1.16.15
- [etcd](https://github.com/coreos/etcd) v3.4.13 - [etcd](https://github.com/coreos/etcd) v3.3.12
- [docker](https://www.docker.com/) v19.03 (see note) - [docker](https://www.docker.com/) v18.06 (see note)
- [containerd](https://containerd.io/) v1.3.9 - [containerd](https://containerd.io/) v1.2.13
- [cri-o](http://cri-o.io/) v1.19 (experimental: see [CRI-O Note](docs/cri-o.md). Only on fedora, ubuntu and centos based OS) - [cri-o](http://cri-o.io/) v1.14.0 (experimental: see [CRI-O Note](docs/cri-o.md). Only on centos based OS)
- Network Plugin - Network Plugin
- [cni-plugins](https://github.com/containernetworking/plugins) v0.9.0 - [cni-plugins](https://github.com/containernetworking/plugins) v0.8.6
- [calico](https://github.com/projectcalico/calico) v3.16.9 - [calico](https://github.com/projectcalico/calico) v3.7.3
- [canal](https://github.com/projectcalico/canal) (given calico/flannel versions) - [canal](https://github.com/projectcalico/canal) (given calico/flannel versions)
- [cilium](https://github.com/cilium/cilium) v1.8.8 - [cilium](https://github.com/cilium/cilium) v1.5.5
- [flanneld](https://github.com/coreos/flannel) v0.13.0 - [contiv](https://github.com/contiv/install) v1.2.1
- [kube-ovn](https://github.com/alauda/kube-ovn) v1.6.1 - [flanneld](https://github.com/coreos/flannel) v0.11.0
- [kube-router](https://github.com/cloudnativelabs/kube-router) v1.1.1 - [kube-router](https://github.com/cloudnativelabs/kube-router) v0.2.5
- [multus](https://github.com/intel/multus-cni) v3.7.0 - [multus](https://github.com/intel/multus-cni) v3.2.1
- [ovn4nfv](https://github.com/opnfv/ovn4nfv-k8s-plugin) v1.1.0 - [weave](https://github.com/weaveworks/weave) v2.5.2
- [weave](https://github.com/weaveworks/weave) v2.7.0
- Application - Application
- [ambassador](https://github.com/datawire/ambassador): v1.5
- [cephfs-provisioner](https://github.com/kubernetes-incubator/external-storage) v2.1.0-k8s1.11 - [cephfs-provisioner](https://github.com/kubernetes-incubator/external-storage) v2.1.0-k8s1.11
- [rbd-provisioner](https://github.com/kubernetes-incubator/external-storage) v2.1.1-k8s1.11 - [rbd-provisioner](https://github.com/kubernetes-incubator/external-storage) v2.1.1-k8s1.11
- [cert-manager](https://github.com/jetstack/cert-manager) v0.16.1 - [cert-manager](https://github.com/jetstack/cert-manager) v0.11.0
- [coredns](https://github.com/coredns/coredns) v1.7.0 - [coredns](https://github.com/coredns/coredns) v1.6.0
- [ingress-nginx](https://github.com/kubernetes/ingress-nginx) v0.41.2 - [ingress-nginx](https://github.com/kubernetes/ingress-nginx) v0.26.1
Note: The list of available docker version is 18.09, 19.03 and 20.10. The recommended docker version is 19.03. The kubelet might break on docker's non-standard version numbering (it no longer uses semantic versioning). To ensure auto-updates don't break your cluster look into e.g. yum versionlock plugin or apt pin). Note: The list of validated [docker versions](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.16.md) was updated to 1.13.1, 17.03, 17.06, 17.09, 18.06, 18.09. kubeadm now properly recognizes Docker 18.09.0 and newer, but still treats 18.06 as the default supported version. The kubelet might break on docker's non-standard version numbering (it no longer uses semantic versioning). To ensure auto-updates don't break your cluster look into e.g. yum versionlock plugin or apt pin).
## Requirements ## Requirements
- **Minimum required version of Kubernetes is v1.18** - **Minimum required version of Kubernetes is v1.15**
- **Ansible v2.9.x, Jinja 2.11+ and python-netaddr is installed on the machine that will run Ansible commands, Ansible 2.10.x is not supported for now** - **Ansible v2.7.16 and python-netaddr is installed on the machine that will run Ansible commands**
- The target servers must have **access to the Internet** in order to pull docker images. Otherwise, additional configuration is required (See [Offline Environment](docs/offline-environment.md)) - **Jinja 2.9 (or newer) is required to run the Ansible Playbooks**
- The target servers must have **access to the Internet** in order to pull docker images. Otherwise, additional configuration is required (See [Offline Environment](https://github.com/kubernetes-sigs/kubespray/blob/master/docs/downloads.md#offline-environment))
- The target servers are configured to allow **IPv4 forwarding**. - The target servers are configured to allow **IPv4 forwarding**.
- **Your ssh key must be copied** to all the servers part of your inventory.
- The **firewalls are not managed**, you'll need to implement your own rules the way you used to. - The **firewalls are not managed**, you'll need to implement your own rules the way you used to.
in order to avoid any issue during deployment you should disable your firewall. in order to avoid any issue during deployment you should disable your firewall.
- If kubespray is ran from non-root user account, correct privilege escalation method - If kubespray is ran from non-root user account, correct privilege escalation method
@@ -168,16 +164,14 @@ You can choose between 10 network plugins. (default: `calico`, except Vagrant us
- [flannel](docs/flannel.md): gre/vxlan (layer 2) networking. - [flannel](docs/flannel.md): gre/vxlan (layer 2) networking.
- [Calico](https://docs.projectcalico.org/latest/introduction/) is a networking and network policy provider. Calico supports a flexible set of networking options - [calico](docs/calico.md): bgp (layer 3) networking.
designed to give you the most efficient networking across a range of situations, including non-overlay
and overlay networks, with or without BGP. Calico uses the same engine to enforce network policy for hosts,
pods, and (if using Istio and Envoy) applications at the service mesh layer.
- [canal](https://github.com/projectcalico/canal): a composition of calico and flannel plugins. - [canal](https://github.com/projectcalico/canal): a composition of calico and flannel plugins.
- [cilium](http://docs.cilium.io/en/latest/): layer 3/4 networking (as well as layer 7 to protect and secure application protocols), supports dynamic insertion of BPF bytecode into the Linux kernel to implement security services, networking and visibility logic. - [cilium](http://docs.cilium.io/en/latest/): layer 3/4 networking (as well as layer 7 to protect and secure application protocols), supports dynamic insertion of BPF bytecode into the Linux kernel to implement security services, networking and visibility logic.
- [ovn4nfv](docs/ovn4nfv.md): [ovn4nfv-k8s-plugins](https://github.com/opnfv/ovn4nfv-k8s-plugin) is the network controller, OVS agent and CNI server to offer basic SFC and OVN overlay networking. - [contiv](docs/contiv.md): supports vlan, vxlan, bgp and Cisco SDN networking. This plugin is able to
apply firewall policies, segregate containers in multiple network and bridging pods onto physical networks.
- [weave](docs/weave.md): Weave is a lightweight container overlay network that doesn't require an external K/V database cluster. - [weave](docs/weave.md): Weave is a lightweight container overlay network that doesn't require an external K/V database cluster.
(Please refer to `weave` [troubleshooting documentation](https://www.weave.works/docs/net/latest/troubleshooting/)). (Please refer to `weave` [troubleshooting documentation](https://www.weave.works/docs/net/latest/troubleshooting/)).
@@ -197,18 +191,12 @@ The choice is defined with the variable `kube_network_plugin`. There is also an
option to leverage built-in cloud provider networking instead. option to leverage built-in cloud provider networking instead.
See also [Network checker](docs/netcheck.md). See also [Network checker](docs/netcheck.md).
## Ingress Plugins
- [ambassador](docs/ambassador.md): the Ambassador Ingress Controller and API gateway.
- [nginx](https://kubernetes.github.io/ingress-nginx): the NGINX Ingress Controller.
## Community docs and resources ## Community docs and resources
- [kubernetes.io/docs/setup/production-environment/tools/kubespray/](https://kubernetes.io/docs/setup/production-environment/tools/kubespray/) - [kubernetes.io/docs/setup/production-environment/tools/kubespray/](https://kubernetes.io/docs/setup/production-environment/tools/kubespray/)
- [kubespray, monitoring and logging](https://github.com/gregbkr/kubernetes-kargo-logging-monitoring) by @gregbkr - [kubespray, monitoring and logging](https://github.com/gregbkr/kubernetes-kargo-logging-monitoring) by @gregbkr
- [Deploy Kubernetes w/ Ansible & Terraform](https://rsmitty.github.io/Terraform-Ansible-Kubernetes/) by @rsmitty - [Deploy Kubernetes w/ Ansible & Terraform](https://rsmitty.github.io/Terraform-Ansible-Kubernetes/) by @rsmitty
- [Deploy a Kubernetes Cluster with Kubespray (video)](https://www.youtube.com/watch?v=CJ5G4GpqDy0) - [Deploy a Kubernetes Cluster with Kubespray (video)](https://www.youtube.com/watch?v=N9q51JgbWu8)
## Tools and projects on top of Kubespray ## Tools and projects on top of Kubespray
@@ -217,8 +205,7 @@ See also [Network checker](docs/netcheck.md).
## CI Tests ## CI Tests
[![Build graphs](https://gitlab.com/kargo-ci/kubernetes-sigs-kubespray/badges/master/pipeline.svg)](https://gitlab.com/kargo-ci/kubernetes-sigs-kubespray/pipelines) [![Build graphs](https://gitlab.com/kargo-ci/kubernetes-sigs-kubespray/badges/master/build.svg)](https://gitlab.com/kargo-ci/kubernetes-sigs-kubespray/pipelines)
CI/end-to-end tests sponsored by: [CNCF](https://cncf.io), [Packet](https://www.packet.com/), [OVHcloud](https://www.ovhcloud.com/), [ELASTX](https://elastx.se/).
CI/end-to-end tests sponsored by Google (GCE)
See the [test matrix](docs/test_cases.md) for details. See the [test matrix](docs/test_cases.md) for details.

View File

@@ -4,45 +4,40 @@ The Kubespray Project is released on an as-needed basis. The process is as follo
1. An issue is proposing a new release with a changelog since the last release 1. An issue is proposing a new release with a changelog since the last release
2. At least one of the [approvers](OWNERS_ALIASES) must approve this release 2. At least one of the [approvers](OWNERS_ALIASES) must approve this release
3. The `kube_version_min_required` variable is set to `n-1` 3. An approver creates [new release in GitHub](https://github.com/kubernetes-sigs/kubespray/releases/new) using a version and tag name like `vX.Y.Z` and attaching the release notes
4. Remove hashes for [EOL versions](https://github.com/kubernetes/sig-release/blob/master/releases/patch-releases.md) of kubernetes from `*_checksums` variables. 4. An approver creates a release branch in the form `release-vX.Y`
5. An approver creates [new release in GitHub](https://github.com/kubernetes-sigs/kubespray/releases/new) using a version and tag name like `vX.Y.Z` and attaching the release notes 5. The corresponding version of [quay.io/kubespray/kubespray:vX.Y.Z](https://quay.io/repository/kubespray/kubespray) docker image is built and tagged
6. An approver creates a release branch in the form `release-X.Y` 6. The `KUBESPRAY_VERSION` variable is updated in `.gitlab-ci.yml`
7. The corresponding version of [quay.io/kubespray/kubespray:vX.Y.Z](https://quay.io/repository/kubespray/kubespray) and [quay.io/kubespray/vagrant:vX.Y.Z](https://quay.io/repository/kubespray/vagrant) docker images are built and tagged 7. The release issue is closed
8. The `KUBESPRAY_VERSION` variable is updated in `.gitlab-ci.yml` 8. An announcement email is sent to `kubernetes-dev@googlegroups.com` with the subject `[ANNOUNCE] Kubespray $VERSION is released`
9. The release issue is closed
10. An announcement email is sent to `kubernetes-dev@googlegroups.com` with the subject `[ANNOUNCE] Kubespray $VERSION is released`
11. The topic of the #kubespray channel is updated with `vX.Y.Z is released! | ...`
## Major/minor releases and milestones ## Major/minor releases, merge freezes and milestones
* For major releases (vX.Y) Kubespray maintains one branch (`release-X.Y`). Minor releases (vX.Y.Z) are available only as tags. * Kubespray maintains one branch for major releases (vX.Y). Minor releases are available only as tags.
* Security patches and bugs might be backported. * Security patches and bugs might be backported.
* Fixes for major releases (vX.Y) and minor releases (vX.Y.Z) are delivered * Fixes for major releases (vX.x.0) and minor releases (vX.Y.x) are delivered
via maintenance releases (vX.Y.Z) and assigned to the corresponding open via maintenance releases (vX.Y.Z) and assigned to the corresponding open
[GitHub milestone](https://github.com/kubernetes-sigs/kubespray/milestones). milestone (vX.Y). That milestone remains open for the major/minor releases
That milestone remains open for the major/minor releases support lifetime, support lifetime, which ends once the milestone closed. Then only a next major
which ends once the milestone is closed. Then only a next major or minor release or minor release can be done.
can be done.
* Kubespray major and minor releases are bound to the given `kube_version` major/minor * Kubespray major and minor releases are bound to the given ``kube_version`` major/minor
version numbers and other components' arbitrary versions, like etcd or network plugins. version numbers and other components' arbitrary versions, like etcd or network plugins.
Older or newer component versions are not supported and not tested for the given Older or newer versions are not supported and not tested for the given release.
release (even if included in the checksum variables, like `kubeadm_checksums`).
* There is no unstable releases and no APIs, thus Kubespray doesn't follow * There is no unstable releases and no APIs, thus Kubespray doesn't follow
[semver](https://semver.org/). Every version describes only a stable release. [semver](http://semver.org/). Every version describes only a stable release.
Breaking changes, if any introduced by changed defaults or non-contrib ansible roles' Breaking changes, if any introduced by changed defaults or non-contrib ansible roles'
playbooks, shall be described in the release notes. Other breaking changes, if any in playbooks, shall be described in the release notes. Other breaking changes, if any in
the contributed addons or bound versions of Kubernetes and other components, are the contributed addons or bound versions of Kubernetes and other components, are
considered out of Kubespray scope and are up to the components' teams to deal with and considered out of Kubespray scope and are up to the components' teams to deal with and
document. document.
* Minor releases can change components' versions, but not the major `kube_version`. * Minor releases can change components' versions, but not the major ``kube_version``.
Greater `kube_version` requires a new major or minor release. For example, if Kubespray v2.0.0 Greater ``kube_version`` requires a new major or minor release. For example, if Kubespray v2.0.0
is bound to `kube_version: 1.4.x`, `calico_version: 0.22.0`, `etcd_version: v3.0.6`, is bound to ``kube_version: 1.4.x``, ``calico_version: 0.22.0``, ``etcd_version: v3.0.6``,
then Kubespray v2.1.0 may be bound to only minor changes to `kube_version`, like v1.5.1 then Kubespray v2.1.0 may be bound to only minor changes to ``kube_version``, like v1.5.1
and *any* changes to other components, like etcd v4, or calico 1.2.3. and *any* changes to other components, like etcd v4, or calico 1.2.3.
And Kubespray v3.x.x shall be bound to `kube_version: 2.x.x` respectively. And Kubespray v3.x.x shall be bound to ``kube_version: 2.x.x`` respectively.

View File

@@ -1,13 +1,13 @@
# Defined below are the security contacts for this repo. # Defined below are the security contacts for this repo.
# #
# They are the contact point for the Product Security Committee to reach out # They are the contact point for the Product Security Team to reach out
# to for triaging and handling of incoming issues. # to for triaging and handling of incoming issues.
# #
# The below names agree to abide by the # The below names agree to abide by the
# [Embargo Policy](https://git.k8s.io/security/private-distributors-list.md#embargo-policy) # [Embargo Policy](https://github.com/kubernetes/sig-release/blob/master/security-release-process-documentation/security-release-process.md#embargo-policy)
# and will be removed and replaced if they violate that agreement. # and will be removed and replaced if they violate that agreement.
# #
# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE # DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
# INSTRUCTIONS AT https://kubernetes.io/security/ # INSTRUCTIONS AT https://kubernetes.io/security/
atoms atoms
mattymo mattymo

138
Vagrantfile vendored
View File

@@ -7,74 +7,63 @@ require 'fileutils'
Vagrant.require_version ">= 2.0.0" Vagrant.require_version ">= 2.0.0"
CONFIG = File.join(File.dirname(__FILE__), ENV['KUBESPRAY_VAGRANT_CONFIG'] || 'vagrant/config.rb') CONFIG = File.join(File.dirname(__FILE__), "vagrant/config.rb")
FLATCAR_URL_TEMPLATE = "https://%s.release.flatcar-linux.net/amd64-usr/current/flatcar_production_vagrant.json" COREOS_URL_TEMPLATE = "https://storage.googleapis.com/%s.release.core-os.net/amd64-usr/current/coreos_production_vagrant.json"
# Uniq disk UUID for libvirt # Uniq disk UUID for libvirt
DISK_UUID = Time.now.utc.to_i DISK_UUID = Time.now.utc.to_i
SUPPORTED_OS = { SUPPORTED_OS = {
"flatcar-stable" => {box: "flatcar-stable", user: "core", box_url: FLATCAR_URL_TEMPLATE % ["stable"]}, "coreos-stable" => {box: "coreos-stable", user: "core", box_url: COREOS_URL_TEMPLATE % ["stable"]},
"flatcar-beta" => {box: "flatcar-beta", user: "core", box_url: FLATCAR_URL_TEMPLATE % ["beta"]}, "coreos-alpha" => {box: "coreos-alpha", user: "core", box_url: COREOS_URL_TEMPLATE % ["alpha"]},
"flatcar-alpha" => {box: "flatcar-alpha", user: "core", box_url: FLATCAR_URL_TEMPLATE % ["alpha"]}, "coreos-beta" => {box: "coreos-beta", user: "core", box_url: COREOS_URL_TEMPLATE % ["beta"]},
"flatcar-edge" => {box: "flatcar-edge", user: "core", box_url: FLATCAR_URL_TEMPLATE % ["edge"]}, "ubuntu1604" => {box: "generic/ubuntu1604", user: "vagrant"},
"ubuntu1604" => {box: "generic/ubuntu1604", user: "vagrant"}, "ubuntu1804" => {box: "generic/ubuntu1804", user: "vagrant"},
"ubuntu1804" => {box: "generic/ubuntu1804", user: "vagrant"}, "centos" => {box: "centos/7", user: "vagrant"},
"ubuntu2004" => {box: "generic/ubuntu2004", user: "vagrant"}, "centos-bento" => {box: "bento/centos-7.6", user: "vagrant"},
"centos" => {box: "centos/7", user: "vagrant"}, "fedora" => {box: "fedora/28-cloud-base", user: "vagrant"},
"centos-bento" => {box: "bento/centos-7.6", user: "vagrant"}, "opensuse" => {box: "opensuse/openSUSE-15.0-x86_64", user: "vagrant"},
"centos8" => {box: "centos/8", user: "vagrant"}, "opensuse-tumbleweed" => {box: "opensuse/openSUSE-Tumbleweed-x86_64", user: "vagrant"},
"centos8-bento" => {box: "bento/centos-8", user: "vagrant"}, "oraclelinux" => {box: "generic/oracle7", user: "vagrant"},
"fedora32" => {box: "fedora/32-cloud-base", user: "vagrant"},
"fedora33" => {box: "fedora/33-cloud-base", user: "vagrant"},
"opensuse" => {box: "bento/opensuse-leap-15.2", user: "vagrant"},
"opensuse-tumbleweed" => {box: "opensuse/Tumbleweed.x86_64", user: "vagrant"},
"oraclelinux" => {box: "generic/oracle7", user: "vagrant"},
"oraclelinux8" => {box: "generic/oracle8", user: "vagrant"},
"rhel7" => {box: "generic/rhel7", user: "vagrant"},
"rhel8" => {box: "generic/rhel8", user: "vagrant"},
} }
# Defaults for config options defined in CONFIG
$num_instances = 3
$instance_name_prefix = "k8s"
$vm_gui = false
$vm_memory = 2048
$vm_cpus = 1
$shared_folders = {}
$forwarded_ports = {}
$subnet = "172.17.8"
$os = "ubuntu1804"
$network_plugin = "flannel"
# Setting multi_networking to true will install Multus: https://github.com/intel/multus-cni
$multi_networking = false
# The first three nodes are etcd servers
$etcd_instances = $num_instances
# The first two nodes are kube masters
$kube_master_instances = $num_instances == 1 ? $num_instances : ($num_instances - 1)
# All nodes are kube nodes
$kube_node_instances = $num_instances
# The following only works when using the libvirt provider
$kube_node_instances_with_disks = false
$kube_node_instances_with_disks_size = "20G"
$kube_node_instances_with_disks_number = 2
$override_disk_size = false
$disk_size = "20GB"
$local_path_provisioner_enabled = false
$local_path_provisioner_claim_root = "/opt/local-path-provisioner/"
$playbook = "cluster.yml"
host_vars = {}
if File.exist?(CONFIG) if File.exist?(CONFIG)
require CONFIG require CONFIG
end end
# Defaults for config options defined in CONFIG
$num_instances ||= 3
$instance_name_prefix ||= "k8s"
$vm_gui ||= false
$vm_memory ||= 2048
$vm_cpus ||= 2
$shared_folders ||= {}
$forwarded_ports ||= {}
$subnet ||= "172.18.8"
$os ||= "ubuntu1804"
$network_plugin ||= "flannel"
# Setting multi_networking to true will install Multus: https://github.com/intel/multus-cni
$multi_networking ||= false
$download_run_once ||= "True"
$download_force_cache ||= "True"
# The first three nodes are etcd servers
$etcd_instances ||= $num_instances
# The first two nodes are kube masters
$kube_master_instances ||= $num_instances == 1 ? $num_instances : ($num_instances - 1)
# All nodes are kube nodes
$kube_node_instances ||= $num_instances
# The following only works when using the libvirt provider
$kube_node_instances_with_disks ||= false
$kube_node_instances_with_disks_size ||= "20G"
$kube_node_instances_with_disks_number ||= 2
$override_disk_size ||= false
$disk_size ||= "20GB"
$local_path_provisioner_enabled ||= false
$local_path_provisioner_claim_root ||= "/opt/local-path-provisioner/"
$libvirt_nested ||= false
$playbook ||= "cluster.yml"
host_vars = {}
$box = SUPPORTED_OS[$os][:box] $box = SUPPORTED_OS[$os][:box]
# if $inventory is not set, try to use example # if $inventory is not set, try to use example
$inventory = "inventory/sample" if ! $inventory $inventory = "inventory/sample" if ! $inventory
@@ -91,10 +80,10 @@ if ! File.exist?(File.join(File.dirname($inventory), "hosts.ini"))
end end
if Vagrant.has_plugin?("vagrant-proxyconf") if Vagrant.has_plugin?("vagrant-proxyconf")
$no_proxy = ENV['NO_PROXY'] || ENV['no_proxy'] || "127.0.0.1,localhost" $no_proxy = ENV['NO_PROXY'] || ENV['no_proxy'] || "127.0.0.1,localhost"
(1..$num_instances).each do |i| (1..$num_instances).each do |i|
$no_proxy += ",#{$subnet}.#{i+100}" $no_proxy += ",#{$subnet}.#{i+100}"
end end
end end
Vagrant.configure("2") do |config| Vagrant.configure("2") do |config|
@@ -144,12 +133,9 @@ Vagrant.configure("2") do |config|
vb.gui = $vm_gui vb.gui = $vm_gui
vb.linked_clone = true vb.linked_clone = true
vb.customize ["modifyvm", :id, "--vram", "8"] # ubuntu defaults to 256 MB which is a waste of precious RAM vb.customize ["modifyvm", :id, "--vram", "8"] # ubuntu defaults to 256 MB which is a waste of precious RAM
vb.customize ["modifyvm", :id, "--audio", "none"]
end end
node.vm.provider :libvirt do |lv| node.vm.provider :libvirt do |lv|
lv.nested = $libvirt_nested
lv.cpu_mode = "host-model"
lv.memory = $vm_memory lv.memory = $vm_memory
lv.cpus = $vm_cpus lv.cpus = $vm_cpus
lv.default_prefix = 'kubespray' lv.default_prefix = 'kubespray'
@@ -179,18 +165,9 @@ Vagrant.configure("2") do |config|
node.vm.network "forwarded_port", guest: guest, host: host, auto_correct: true node.vm.network "forwarded_port", guest: guest, host: host, auto_correct: true
end end
if ["rhel7","rhel8"].include? $os node.vm.synced_folder ".", "/vagrant", disabled: false, type: "rsync", rsync__args: ['--verbose', '--archive', '--delete', '-z'] , rsync__exclude: ['.git','venv']
# Vagrant synced_folder rsync options cannot be used for RHEL boxes as Rsync package cannot $shared_folders.each do |src, dst|
# be installed until the host is registered with a valid Red Hat support subscription node.vm.synced_folder src, dst, type: "rsync", rsync__args: ['--verbose', '--archive', '--delete', '-z']
node.vm.synced_folder ".", "/vagrant", disabled: false
$shared_folders.each do |src, dst|
node.vm.synced_folder src, dst
end
else
node.vm.synced_folder ".", "/vagrant", disabled: false, type: "rsync", rsync__args: ['--verbose', '--archive', '--delete', '-z'] , rsync__exclude: ['.git','venv']
$shared_folders.each do |src, dst|
node.vm.synced_folder src, dst, type: "rsync", rsync__args: ['--verbose', '--archive', '--delete', '-z']
end
end end
ip = "#{$subnet}.#{i+100}" ip = "#{$subnet}.#{i+100}"
@@ -199,24 +176,19 @@ Vagrant.configure("2") do |config|
# Disable swap for each vm # Disable swap for each vm
node.vm.provision "shell", inline: "swapoff -a" node.vm.provision "shell", inline: "swapoff -a"
# Disable firewalld on oraclelinux/redhat vms
if ["oraclelinux","oraclelinux8","rhel7","rhel8"].include? $os
node.vm.provision "shell", inline: "systemctl stop firewalld; systemctl disable firewalld"
end
host_vars[vm_name] = { host_vars[vm_name] = {
"ip": ip, "ip": ip,
"flannel_interface": "eth1", "flannel_interface": "eth1",
"kube_network_plugin": $network_plugin, "kube_network_plugin": $network_plugin,
"kube_network_plugin_multus": $multi_networking, "kube_network_plugin_multus": $multi_networking,
"download_run_once": $download_run_once, "download_run_once": "True",
"download_localhost": "False", "download_localhost": "False",
"download_cache_dir": ENV['HOME'] + "/kubespray_cache", "download_cache_dir": ENV['HOME'] + "/kubespray_cache",
# Make kubespray cache even when download_run_once is false # Make kubespray cache even when download_run_once is false
"download_force_cache": $download_force_cache, "download_force_cache": "True",
# Keeping the cache on the nodes can improve provisioning speed while debugging kubespray # Keeping the cache on the nodes can improve provisioning speed while debugging kubespray
"download_keep_remote_cache": "False", "download_keep_remote_cache": "False",
"docker_rpm_keepcache": "1", "docker_keepcache": "1",
# These two settings will put kubectl and admin.config in $inventory/artifacts # These two settings will put kubectl and admin.config in $inventory/artifacts
"kubeconfig_localhost": "True", "kubeconfig_localhost": "True",
"kubectl_localhost": "True", "kubectl_localhost": "True",

View File

@@ -1,2 +1,2 @@
--- ---
theme: jekyll-theme-slate theme: jekyll-theme-slate

View File

@@ -11,9 +11,7 @@ host_key_checking=False
gathering = smart gathering = smart
fact_caching = jsonfile fact_caching = jsonfile
fact_caching_connection = /tmp fact_caching_connection = /tmp
fact_caching_timeout = 7200 stdout_callback = skippy
stdout_callback = default
display_skipped_hosts = no
library = ./library library = ./library
callback_whitelist = profile_tasks callback_whitelist = profile_tasks
roles_path = roles:$VIRTUAL_ENV/usr/local/share/kubespray/roles:$VIRTUAL_ENV/usr/local/share/ansible/roles:/usr/share/kubespray/roles roles_path = roles:$VIRTUAL_ENV/usr/local/share/kubespray/roles:$VIRTUAL_ENV/usr/local/share/ansible/roles:/usr/share/kubespray/roles

View File

@@ -1,17 +0,0 @@
---
- hosts: localhost
gather_facts: false
become: no
vars:
minimal_ansible_version: 2.9.0
maximal_ansible_version: 2.10.0
ansible_connection: local
tasks:
- name: "Check {{ minimal_ansible_version }} <= Ansible version < {{ maximal_ansible_version }}"
assert:
msg: "Ansible must be between {{ minimal_ansible_version }} and {{ maximal_ansible_version }}"
that:
- ansible_version.string is version(minimal_ansible_version, ">=")
- ansible_version.string is version(maximal_ansible_version, "<")
tags:
- check

View File

@@ -1,43 +1,44 @@
--- ---
- name: Check ansible version - hosts: localhost
import_playbook: ansible_version.yml gather_facts: false
become: no
tasks:
- name: "Check ansible version >=2.7.8"
assert:
msg: "Ansible must be v2.7.8 or higher"
that:
- ansible_version.string is version("2.7.8", ">=")
tags:
- check
vars:
ansible_connection: local
- hosts: bastion[0] - hosts: bastion[0]
gather_facts: False gather_facts: False
environment: "{{ proxy_disable_env }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- { role: bastion-ssh-config, tags: ["localhost", "bastion"] } - { role: bastion-ssh-config, tags: ["localhost", "bastion"]}
- hosts: k8s-cluster:etcd - hosts: k8s-cluster:etcd
strategy: linear
any_errors_fatal: "{{ any_errors_fatal | default(true) }}" any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
gather_facts: false gather_facts: false
environment: "{{ proxy_disable_env }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- { role: bootstrap-os, tags: bootstrap-os} - { role: bootstrap-os, tags: bootstrap-os}
- name: Gather facts
tags: always
import_playbook: facts.yml
- hosts: k8s-cluster:etcd - hosts: k8s-cluster:etcd
gather_facts: False
any_errors_fatal: "{{ any_errors_fatal | default(true) }}" any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- { role: kubernetes/preinstall, tags: preinstall } - { role: kubernetes/preinstall, tags: preinstall }
- { role: "container-engine", tags: "container-engine", when: deploy_container_engine|default(true) } - { role: "container-engine", tags: "container-engine", when: deploy_container_engine|default(true) }
- { role: download, tags: download, when: "not skip_downloads" } - { role: download, tags: download, when: "not skip_downloads" }
environment: "{{ proxy_env }}"
- hosts: etcd - hosts: etcd
gather_facts: False
any_errors_fatal: "{{ any_errors_fatal | default(true) }}" any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- role: etcd - role: etcd
tags: etcd tags: etcd
vars: vars:
@@ -46,11 +47,9 @@
when: not etcd_kubeadm_enabled| default(false) when: not etcd_kubeadm_enabled| default(false)
- hosts: k8s-cluster - hosts: k8s-cluster
gather_facts: False
any_errors_fatal: "{{ any_errors_fatal | default(true) }}" any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- role: etcd - role: etcd
tags: etcd tags: etcd
vars: vars:
@@ -59,73 +58,59 @@
when: not etcd_kubeadm_enabled| default(false) when: not etcd_kubeadm_enabled| default(false)
- hosts: k8s-cluster - hosts: k8s-cluster
gather_facts: False
any_errors_fatal: "{{ any_errors_fatal | default(true) }}" any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- { role: kubernetes/node, tags: node } - { role: kubernetes/node, tags: node }
environment: "{{ proxy_env }}"
- hosts: kube-master - hosts: kube-master
gather_facts: False
any_errors_fatal: "{{ any_errors_fatal | default(true) }}" any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- { role: kubernetes/master, tags: master } - { role: kubernetes/master, tags: master }
- { role: kubernetes/client, tags: client } - { role: kubernetes/client, tags: client }
- { role: kubernetes-apps/cluster_roles, tags: cluster-roles } - { role: kubernetes-apps/cluster_roles, tags: cluster-roles }
- hosts: k8s-cluster - hosts: k8s-cluster
gather_facts: False
any_errors_fatal: "{{ any_errors_fatal | default(true) }}" any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- { role: kubernetes/kubeadm, tags: kubeadm} - { role: kubernetes/kubeadm, tags: kubeadm}
- { role: network_plugin, tags: network } - { role: network_plugin, tags: network }
- { role: kubernetes/node-label, tags: node-label } - { role: kubernetes/node-label }
- hosts: calico-rr - hosts: calico-rr
gather_facts: False
any_errors_fatal: "{{ any_errors_fatal | default(true) }}" any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- { role: network_plugin/calico/rr, tags: ['network', 'calico_rr'] } - { role: network_plugin/calico/rr, tags: ['network', 'calico_rr']}
- hosts: kube-master[0] - hosts: kube-master[0]
gather_facts: False
any_errors_fatal: "{{ any_errors_fatal | default(true) }}" any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- { role: win_nodes/kubernetes_patch, tags: ["master", "win_nodes"] } - { role: kubernetes-apps/rotate_tokens, tags: rotate_tokens, when: "secret_changed|default(false)" }
- { role: win_nodes/kubernetes_patch, tags: ["master", "win_nodes"]}
- hosts: kube-master - hosts: kube-master
gather_facts: False
any_errors_fatal: "{{ any_errors_fatal | default(true) }}" any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- { role: kubernetes-apps/external_cloud_controller, tags: external-cloud-controller }
- { role: kubernetes-apps/network_plugin, tags: network } - { role: kubernetes-apps/network_plugin, tags: network }
- { role: kubernetes-apps/policy_controller, tags: policy-controller } - { role: kubernetes-apps/policy_controller, tags: policy-controller }
- { role: kubernetes-apps/ingress_controller, tags: ingress-controller } - { role: kubernetes-apps/ingress_controller, tags: ingress-controller }
- { role: kubernetes-apps/external_provisioner, tags: external-provisioner } - { role: kubernetes-apps/external_provisioner, tags: external-provisioner }
- hosts: kube-master - hosts: kube-master
gather_facts: False
any_errors_fatal: "{{ any_errors_fatal | default(true) }}" any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- { role: kubernetes-apps, tags: apps } - { role: kubernetes-apps, tags: apps }
environment: "{{ proxy_env }}"
- hosts: k8s-cluster - hosts: k8s-cluster
gather_facts: False
any_errors_fatal: "{{ any_errors_fatal | default(true) }}" any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
environment: "{{ proxy_disable_env }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- { role: kubernetes/preinstall, when: "dns_mode != 'none' and resolvconf_mode == 'host_resolvconf'", tags: resolvconf, dns_late: true } - { role: kubernetes/preinstall, when: "dns_mode != 'none' and resolvconf_mode == 'host_resolvconf'", tags: resolvconf, dns_late: true }

View File

@@ -1 +0,0 @@
boto3 # Apache-2.0

View File

@@ -15,23 +15,22 @@ Resource Group. It will not install Kubernetes itself, this has to be done in a
## Configuration through group_vars/all ## Configuration through group_vars/all
You have to modify at least two variables in group_vars/all. The one is the **cluster_name** variable, it must be globally You have to modify at least one variable in group_vars/all, which is the **cluster_name** variable. It must be globally
unique due to some restrictions in Azure. The other one is the **ssh_public_keys** variable, it must be your ssh public unique due to some restrictions in Azure. Most other variables should be self explanatory if you have some basic Kubernetes
key to access your azure virtual machines. Most other variables should be self explanatory if you have some basic Kubernetes
experience. experience.
## Bastion host ## Bastion host
You can enable the use of a Bastion Host by changing **use_bastion** in group_vars/all to **true**. The generated You can enable the use of a Bastion Host by changing **use_bastion** in group_vars/all to **true**. The generated
templates will then include an additional bastion VM which can then be used to connect to the masters and nodes. The option templates will then include an additional bastion VM which can then be used to connect to the masters and nodes. The option
also removes all public IPs from all other VMs. also removes all public IPs from all other VMs.
## Generating and applying ## Generating and applying
To generate and apply the templates, call: To generate and apply the templates, call:
```shell ```shell
./apply-rg.sh <resource_group_name> $ ./apply-rg.sh <resource_group_name>
``` ```
If you change something in the configuration (e.g. number of nodes) later, you can call this again and Azure will If you change something in the configuration (e.g. number of nodes) later, you can call this again and Azure will
@@ -42,23 +41,24 @@ take care about creating/modifying whatever is needed.
If you need to delete all resources from a resource group, simply call: If you need to delete all resources from a resource group, simply call:
```shell ```shell
./clear-rg.sh <resource_group_name> $ ./clear-rg.sh <resource_group_name>
``` ```
**WARNING** this really deletes everything from your resource group, including everything that was later created by you! **WARNING** this really deletes everything from your resource group, including everything that was later created by you!
## Generating an inventory for kubespray ## Generating an inventory for kubespray
After you have applied the templates, you can generate an inventory with this call: After you have applied the templates, you can generate an inventory with this call:
```shell ```shell
./generate-inventory.sh <resource_group_name> $ ./generate-inventory.sh <resource_group_name>
``` ```
It will create the file ./inventory which can then be used with kubespray, e.g.: It will create the file ./inventory which can then be used with kubespray, e.g.:
```shell ```shell
cd kubespray-root-dir $ cd kubespray-root-dir
sudo pip3 install -r requirements.txt $ ansible-playbook -i contrib/azurerm/inventory -u devops --become -e "@inventory/sample/group_vars/all.yml" cluster.yml
ansible-playbook -i contrib/azurerm/inventory -u devops --become -e "@inventory/sample/group_vars/all/all.yml" cluster.yml
``` ```

View File

@@ -9,11 +9,18 @@ if [ "$AZURE_RESOURCE_GROUP" == "" ]; then
exit 1 exit 1
fi fi
ansible-playbook generate-templates.yml if az &>/dev/null; then
echo "azure cli 2.0 found, using it instead of 1.0"
az deployment group create --template-file ./.generated/network.json -g $AZURE_RESOURCE_GROUP ./apply-rg_2.sh "$AZURE_RESOURCE_GROUP"
az deployment group create --template-file ./.generated/storage.json -g $AZURE_RESOURCE_GROUP elif azure &>/dev/null; then
az deployment group create --template-file ./.generated/availability-sets.json -g $AZURE_RESOURCE_GROUP ansible-playbook generate-templates.yml
az deployment group create --template-file ./.generated/bastion.json -g $AZURE_RESOURCE_GROUP
az deployment group create --template-file ./.generated/masters.json -g $AZURE_RESOURCE_GROUP azure group deployment create -f ./.generated/network.json -g $AZURE_RESOURCE_GROUP
az deployment group create --template-file ./.generated/minions.json -g $AZURE_RESOURCE_GROUP azure group deployment create -f ./.generated/storage.json -g $AZURE_RESOURCE_GROUP
azure group deployment create -f ./.generated/availability-sets.json -g $AZURE_RESOURCE_GROUP
azure group deployment create -f ./.generated/bastion.json -g $AZURE_RESOURCE_GROUP
azure group deployment create -f ./.generated/masters.json -g $AZURE_RESOURCE_GROUP
azure group deployment create -f ./.generated/minions.json -g $AZURE_RESOURCE_GROUP
else
echo "Azure cli not found"
fi

19
contrib/azurerm/apply-rg_2.sh Executable file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/env bash
set -e
AZURE_RESOURCE_GROUP="$1"
if [ "$AZURE_RESOURCE_GROUP" == "" ]; then
echo "AZURE_RESOURCE_GROUP is missing"
exit 1
fi
ansible-playbook generate-templates.yml
az group deployment create --template-file ./.generated/network.json -g $AZURE_RESOURCE_GROUP
az group deployment create --template-file ./.generated/storage.json -g $AZURE_RESOURCE_GROUP
az group deployment create --template-file ./.generated/availability-sets.json -g $AZURE_RESOURCE_GROUP
az group deployment create --template-file ./.generated/bastion.json -g $AZURE_RESOURCE_GROUP
az group deployment create --template-file ./.generated/masters.json -g $AZURE_RESOURCE_GROUP
az group deployment create --template-file ./.generated/minions.json -g $AZURE_RESOURCE_GROUP

View File

@@ -9,6 +9,10 @@ if [ "$AZURE_RESOURCE_GROUP" == "" ]; then
exit 1 exit 1
fi fi
ansible-playbook generate-templates.yml if az &>/dev/null; then
echo "azure cli 2.0 found, using it instead of 1.0"
az group deployment create -g "$AZURE_RESOURCE_GROUP" --template-file ./.generated/clear-rg.json --mode Complete ./clear-rg_2.sh "$AZURE_RESOURCE_GROUP"
else
ansible-playbook generate-templates.yml
azure group deployment create -g "$AZURE_RESOURCE_GROUP" -f ./.generated/clear-rg.json -m Complete
fi

14
contrib/azurerm/clear-rg_2.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/env bash
set -e
AZURE_RESOURCE_GROUP="$1"
if [ "$AZURE_RESOURCE_GROUP" == "" ]; then
echo "AZURE_RESOURCE_GROUP is missing"
exit 1
fi
ansible-playbook generate-templates.yml
az group deployment create -g "$AZURE_RESOURCE_GROUP" --template-file ./.generated/clear-rg.json --mode Complete

View File

@@ -1,6 +1,6 @@
--- ---
- name: Query Azure VMs # noqa 301 - name: Query Azure VMs
command: azure vm list-ip-address --json {{ azure_resource_group }} command: azure vm list-ip-address --json {{ azure_resource_group }}
register: vm_list_cmd register: vm_list_cmd

View File

@@ -1,14 +1,14 @@
--- ---
- name: Query Azure VMs IPs # noqa 301 - name: Query Azure VMs IPs
command: az vm list-ip-addresses -o json --resource-group {{ azure_resource_group }} command: az vm list-ip-addresses -o json --resource-group {{ azure_resource_group }}
register: vm_ip_list_cmd register: vm_ip_list_cmd
- name: Query Azure VMs Roles # noqa 301 - name: Query Azure VMs Roles
command: az vm list -o json --resource-group {{ azure_resource_group }} command: az vm list -o json --resource-group {{ azure_resource_group }}
register: vm_list_cmd register: vm_list_cmd
- name: Query Azure Load Balancer Public IP # noqa 301 - name: Query Azure Load Balancer Public IP
command: az network public-ip show -o json -g {{ azure_resource_group }} -n kubernetes-api-pubip command: az network public-ip show -o json -g {{ azure_resource_group }} -n kubernetes-api-pubip
register: lb_pubip_cmd register: lb_pubip_cmd

View File

@@ -6,7 +6,6 @@ to serve as Kubernetes "nodes", which in turn will run
called DIND (Docker-IN-Docker). called DIND (Docker-IN-Docker).
The playbook has two roles: The playbook has two roles:
- dind-host: creates the "nodes" as containers in localhost, with - dind-host: creates the "nodes" as containers in localhost, with
appropriate settings for DIND (privileged, volume mapping for dind appropriate settings for DIND (privileged, volume mapping for dind
storage, etc). storage, etc).
@@ -28,7 +27,7 @@ See below for a complete successful run:
1. Create the node containers 1. Create the node containers
```shell ~~~~
# From the kubespray root dir # From the kubespray root dir
cd contrib/dind cd contrib/dind
pip install -r requirements.txt pip install -r requirements.txt
@@ -37,15 +36,15 @@ ansible-playbook -i hosts dind-cluster.yaml
# Back to kubespray root # Back to kubespray root
cd ../.. cd ../..
``` ~~~~
NOTE: if the playbook run fails with something like below error NOTE: if the playbook run fails with something like below error
message, you may need to specifically set `ansible_python_interpreter`, message, you may need to specifically set `ansible_python_interpreter`,
see `./hosts` file for an example expanded localhost entry. see `./hosts` file for an example expanded localhost entry.
```shell ~~~
failed: [localhost] (item=kube-node1) => {"changed": false, "item": "kube-node1", "msg": "Failed to import docker or docker-py - No module named requests.exceptions. Try `pip install docker` or `pip install docker-py` (Python 2.6)"} failed: [localhost] (item=kube-node1) => {"changed": false, "item": "kube-node1", "msg": "Failed to import docker or docker-py - No module named requests.exceptions. Try `pip install docker` or `pip install docker-py` (Python 2.6)"}
``` ~~~
2. Customize kubespray-dind.yaml 2. Customize kubespray-dind.yaml
@@ -53,33 +52,33 @@ Note that there's coupling between above created node containers
and `kubespray-dind.yaml` settings, in particular regarding selected `node_distro` and `kubespray-dind.yaml` settings, in particular regarding selected `node_distro`
(as set in `group_vars/all/all.yaml`), and docker settings. (as set in `group_vars/all/all.yaml`), and docker settings.
```shell ~~~
$EDITOR contrib/dind/kubespray-dind.yaml $EDITOR contrib/dind/kubespray-dind.yaml
``` ~~~
3. Prepare the inventory and run the playbook 3. Prepare the inventory and run the playbook
```shell ~~~
INVENTORY_DIR=inventory/local-dind INVENTORY_DIR=inventory/local-dind
mkdir -p ${INVENTORY_DIR} mkdir -p ${INVENTORY_DIR}
rm -f ${INVENTORY_DIR}/hosts.ini rm -f ${INVENTORY_DIR}/hosts.ini
CONFIG_FILE=${INVENTORY_DIR}/hosts.ini /tmp/kubespray.dind.inventory_builder.sh CONFIG_FILE=${INVENTORY_DIR}/hosts.ini /tmp/kubespray.dind.inventory_builder.sh
ansible-playbook --become -e ansible_ssh_user=debian -i ${INVENTORY_DIR}/hosts.ini cluster.yml --extra-vars @contrib/dind/kubespray-dind.yaml ansible-playbook --become -e ansible_ssh_user=debian -i ${INVENTORY_DIR}/hosts.ini cluster.yml --extra-vars @contrib/dind/kubespray-dind.yaml
``` ~~~
NOTE: You could also test other distros without editing files by NOTE: You could also test other distros without editing files by
passing `--extra-vars` as per below commandline, passing `--extra-vars` as per below commandline,
replacing `DISTRO` by either `debian`, `ubuntu`, `centos`, `fedora`: replacing `DISTRO` by either `debian`, `ubuntu`, `centos`, `fedora`:
```shell ~~~
cd contrib/dind cd contrib/dind
ansible-playbook -i hosts dind-cluster.yaml --extra-vars node_distro=DISTRO ansible-playbook -i hosts dind-cluster.yaml --extra-vars node_distro=DISTRO
cd ../.. cd ../..
CONFIG_FILE=inventory/local-dind/hosts.ini /tmp/kubespray.dind.inventory_builder.sh CONFIG_FILE=inventory/local-dind/hosts.ini /tmp/kubespray.dind.inventory_builder.sh
ansible-playbook --become -e ansible_ssh_user=DISTRO -i inventory/local-dind/hosts.ini cluster.yml --extra-vars @contrib/dind/kubespray-dind.yaml --extra-vars bootstrap_os=DISTRO ansible-playbook --become -e ansible_ssh_user=DISTRO -i inventory/local-dind/hosts.ini cluster.yml --extra-vars @contrib/dind/kubespray-dind.yaml --extra-vars bootstrap_os=DISTRO
``` ~~~
## Resulting deployment ## Resulting deployment
@@ -90,7 +89,7 @@ from the host where you ran kubespray playbooks.
Running from an Ubuntu Xenial host: Running from an Ubuntu Xenial host:
```shell ~~~
$ uname -a $ uname -a
Linux ip-xx-xx-xx-xx 4.4.0-1069-aws #79-Ubuntu SMP Mon Sep 24 Linux ip-xx-xx-xx-xx 4.4.0-1069-aws #79-Ubuntu SMP Mon Sep 24
15:01:41 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux 15:01:41 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
@@ -150,14 +149,14 @@ kube-system weave-net-xr46t 2/2 Running 0
$ docker exec kube-node1 curl -s http://localhost:31081/api/v1/connectivity_check $ docker exec kube-node1 curl -s http://localhost:31081/api/v1/connectivity_check
{"Message":"All 10 pods successfully reported back to the server","Absent":null,"Outdated":null} {"Message":"All 10 pods successfully reported back to the server","Absent":null,"Outdated":null}
``` ~~~
## Using ./run-test-distros.sh ## Using ./run-test-distros.sh
You can use `./run-test-distros.sh` to run a set of tests via DIND, You can use `./run-test-distros.sh` to run a set of tests via DIND,
and excerpt from this script, to get an idea: and excerpt from this script, to get an idea:
```shell ~~~
# The SPEC file(s) must have two arrays as e.g. # The SPEC file(s) must have two arrays as e.g.
# DISTROS=(debian centos) # DISTROS=(debian centos)
# EXTRAS=( # EXTRAS=(
@@ -170,7 +169,7 @@ and excerpt from this script, to get an idea:
# #
# Each $EXTRAS element will be whitespace split, and passed as --extra-vars # Each $EXTRAS element will be whitespace split, and passed as --extra-vars
# to main kubespray ansible-playbook run. # to main kubespray ansible-playbook run.
``` ~~~
See e.g. `test-some_distros-most_CNIs.env` and See e.g. `test-some_distros-most_CNIs.env` and
`test-some_distros-kube_router_combo.env` in particular for a richer `test-some_distros-kube_router_combo.env` in particular for a richer

View File

@@ -69,7 +69,7 @@
# Running systemd-machine-id-setup doesn't create a unique id for each node container on Debian, # Running systemd-machine-id-setup doesn't create a unique id for each node container on Debian,
# handle manually # handle manually
- name: Re-create unique machine-id (as we may just get what comes in the docker image), needed by some CNIs for mac address seeding (notably weave) # noqa 301 - name: Re-create unique machine-id (as we may just get what comes in the docker image), needed by some CNIs for mac address seeding (notably weave)
raw: | raw: |
echo {{ item | hash('sha1') }} > /etc/machine-id.new echo {{ item | hash('sha1') }} > /etc/machine-id.new
mv -b /etc/machine-id.new /etc/machine-id mv -b /etc/machine-id.new /etc/machine-id

View File

@@ -41,7 +41,6 @@ from ruamel.yaml import YAML
import os import os
import re import re
import subprocess
import sys import sys
ROLES = ['all', 'kube-master', 'kube-node', 'etcd', 'k8s-cluster', ROLES = ['all', 'kube-master', 'kube-node', 'etcd', 'k8s-cluster',
@@ -63,14 +62,13 @@ def get_var_as_bool(name, default):
CONFIG_FILE = os.environ.get("CONFIG_FILE", "./inventory/sample/hosts.yaml") CONFIG_FILE = os.environ.get("CONFIG_FILE", "./inventory/sample/hosts.yaml")
KUBE_MASTERS = int(os.environ.get("KUBE_MASTERS", 2)) KUBE_MASTERS = int(os.environ.get("KUBE_MASTERS_MASTERS", 2))
# Reconfigures cluster distribution at scale # Reconfigures cluster distribution at scale
SCALE_THRESHOLD = int(os.environ.get("SCALE_THRESHOLD", 50)) SCALE_THRESHOLD = int(os.environ.get("SCALE_THRESHOLD", 50))
MASSIVE_SCALE_THRESHOLD = int(os.environ.get("MASSIVE_SCALE_THRESHOLD", 200)) MASSIVE_SCALE_THRESHOLD = int(os.environ.get("SCALE_THRESHOLD", 200))
DEBUG = get_var_as_bool("DEBUG", True) DEBUG = get_var_as_bool("DEBUG", True)
HOST_PREFIX = os.environ.get("HOST_PREFIX", "node") HOST_PREFIX = os.environ.get("HOST_PREFIX", "node")
USE_REAL_HOSTNAME = get_var_as_bool("USE_REAL_HOSTNAME", False)
# Configurable as shell vars end # Configurable as shell vars end
@@ -83,7 +81,7 @@ class KubesprayInventory(object):
if self.config_file: if self.config_file:
try: try:
self.hosts_file = open(config_file, 'r') self.hosts_file = open(config_file, 'r')
self.yaml_config = yaml.load_all(self.hosts_file) self.yaml_config = yaml.load(self.hosts_file)
except OSError: except OSError:
pass pass
@@ -169,7 +167,6 @@ class KubesprayInventory(object):
# FIXME(mattymo): Fix condition where delete then add reuses highest id # FIXME(mattymo): Fix condition where delete then add reuses highest id
next_host_id = highest_host_id + 1 next_host_id = highest_host_id + 1
next_host = ""
all_hosts = existing_hosts.copy() all_hosts = existing_hosts.copy()
for host in changed_hosts: for host in changed_hosts:
@@ -194,14 +191,8 @@ class KubesprayInventory(object):
self.debug("Skipping existing host {0}.".format(ip)) self.debug("Skipping existing host {0}.".format(ip))
continue continue
if USE_REAL_HOSTNAME: next_host = "{0}{1}".format(HOST_PREFIX, next_host_id)
cmd = ("ssh -oStrictHostKeyChecking=no " next_host_id += 1
+ access_ip + " 'hostname -s'")
next_host = subprocess.check_output(cmd, shell=True)
next_host = next_host.strip().decode('ascii')
else:
next_host = "{0}{1}".format(HOST_PREFIX, next_host_id)
next_host_id += 1
all_hosts[next_host] = {'ansible_host': access_ip, all_hosts[next_host] = {'ansible_host': access_ip,
'ip': ip, 'ip': ip,
'access_ip': access_ip} 'access_ip': access_ip}
@@ -238,7 +229,7 @@ class KubesprayInventory(object):
return [ip_address(ip).exploded for ip in range(start, end + 1)] return [ip_address(ip).exploded for ip in range(start, end + 1)]
for host in hosts: for host in hosts:
if '-' in host and not (host.startswith('-') or host[0].isalpha()): if '-' in host and not host.startswith('-'):
start, end = host.strip().split('-') start, end = host.strip().split('-')
try: try:
reworked_hosts.extend(ips(start, end)) reworked_hosts.extend(ips(start, end))
@@ -402,7 +393,6 @@ Configurable env vars:
DEBUG Enable debug printing. Default: True DEBUG Enable debug printing. Default: True
CONFIG_FILE File to write config to Default: ./inventory/sample/hosts.yaml CONFIG_FILE File to write config to Default: ./inventory/sample/hosts.yaml
HOST_PREFIX Host prefix for generated hosts. Default: node HOST_PREFIX Host prefix for generated hosts. Default: node
KUBE_MASTERS Set the number of kube-masters. Default: 2
SCALE_THRESHOLD Separate ETCD role if # of nodes >= 50 SCALE_THRESHOLD Separate ETCD role if # of nodes >= 50
MASSIVE_SCALE_THRESHOLD Separate K8s master and ETCD if # of nodes >= 200 MASSIVE_SCALE_THRESHOLD Separate K8s master and ETCD if # of nodes >= 200
''' # noqa ''' # noqa

View File

@@ -51,7 +51,7 @@ class TestInventory(unittest.TestCase):
groups = ['group1', 'group2'] groups = ['group1', 'group2']
self.inv.ensure_required_groups(groups) self.inv.ensure_required_groups(groups)
for group in groups: for group in groups:
self.assertIn(group, self.inv.yaml_config['all']['children']) self.assertTrue(group in self.inv.yaml_config['all']['children'])
def test_get_host_id(self): def test_get_host_id(self):
hostnames = ['node99', 'no99de01', '01node01', 'node1.domain', hostnames = ['node99', 'no99de01', '01node01', 'node1.domain',
@@ -209,8 +209,8 @@ class TestInventory(unittest.TestCase):
('doesnotbelong2', {'whateveropts=ilike'})]) ('doesnotbelong2', {'whateveropts=ilike'})])
self.inv.yaml_config['all']['hosts'] = existing_hosts self.inv.yaml_config['all']['hosts'] = existing_hosts
self.inv.purge_invalid_hosts(proper_hostnames) self.inv.purge_invalid_hosts(proper_hostnames)
self.assertNotIn( self.assertTrue(
bad_host, self.inv.yaml_config['all']['hosts'].keys()) bad_host not in self.inv.yaml_config['all']['hosts'].keys())
def test_add_host_to_group(self): def test_add_host_to_group(self):
group = 'etcd' group = 'etcd'
@@ -227,8 +227,8 @@ class TestInventory(unittest.TestCase):
host = 'node1' host = 'node1'
self.inv.set_kube_master([host]) self.inv.set_kube_master([host])
self.assertIn( self.assertTrue(
host, self.inv.yaml_config['all']['children'][group]['hosts']) host in self.inv.yaml_config['all']['children'][group]['hosts'])
def test_set_all(self): def test_set_all(self):
hosts = OrderedDict([ hosts = OrderedDict([
@@ -246,8 +246,8 @@ class TestInventory(unittest.TestCase):
self.inv.set_k8s_cluster() self.inv.set_k8s_cluster()
for host in expected_hosts: for host in expected_hosts:
self.assertIn( self.assertTrue(
host, host in
self.inv.yaml_config['all']['children'][group]['children']) self.inv.yaml_config['all']['children'][group]['children'])
def test_set_kube_node(self): def test_set_kube_node(self):
@@ -255,16 +255,16 @@ class TestInventory(unittest.TestCase):
host = 'node1' host = 'node1'
self.inv.set_kube_node([host]) self.inv.set_kube_node([host])
self.assertIn( self.assertTrue(
host, self.inv.yaml_config['all']['children'][group]['hosts']) host in self.inv.yaml_config['all']['children'][group]['hosts'])
def test_set_etcd(self): def test_set_etcd(self):
group = 'etcd' group = 'etcd'
host = 'node1' host = 'node1'
self.inv.set_etcd([host]) self.inv.set_etcd([host])
self.assertIn( self.assertTrue(
host, self.inv.yaml_config['all']['children'][group]['hosts']) host in self.inv.yaml_config['all']['children'][group]['hosts'])
def test_scale_scenario_one(self): def test_scale_scenario_one(self):
num_nodes = 50 num_nodes = 50

View File

@@ -5,7 +5,7 @@ deployment on VMs.
This playbook does not create Virtual Machines, nor does it run Kubespray itself. This playbook does not create Virtual Machines, nor does it run Kubespray itself.
## User creation ### User creation
If you want to create a user for running Kubespray deployment, you should specify If you want to create a user for running Kubespray deployment, you should specify
both `k8s_deployment_user` and `k8s_deployment_user_pkey_path`. both `k8s_deployment_user` and `k8s_deployment_user_pkey_path`.

12
contrib/metallb/README.md Normal file
View File

@@ -0,0 +1,12 @@
# Deploy MetalLB into Kubespray/Kubernetes
```
MetalLB hooks into your Kubernetes cluster, and provides a network load-balancer implementation. In short, it allows you to create Kubernetes services of type “LoadBalancer” in clusters that dont run on a cloud provider, and thus cannot simply hook into paid products to provide load-balancers.
```
This playbook aims to automate [this](https://metallb.universe.tf/concepts/layer2/). It deploys MetalLB into kubernetes and sets up a layer 2 loadbalancer.
## Install
```
Defaults can be found in contrib/metallb/roles/provision/defaults/main.yml. You can override the defaults by copying the contents of this file to somewhere in inventory/mycluster/group_vars such as inventory/mycluster/groups_vars/k8s-cluster/addons.yml and making any adjustments as required.
ansible-playbook --ask-become -i inventory/sample/hosts.ini contrib/metallb/metallb.yml
```

1
contrib/metallb/library Symbolic link
View File

@@ -0,0 +1 @@
../../library

View File

@@ -0,0 +1,6 @@
---
- hosts: kube-master[0]
tags:
- "provision"
roles:
- { role: provision }

View File

@@ -0,0 +1,14 @@
---
metallb:
ip_range: "10.5.0.50-10.5.0.99"
protocol: "layer2"
# additional_address_pools:
# kube_service_pool:
# ip_range: "10.5.1.50-10.5.1.99"
# protocol: "layer2"
# auto_assign: false
limits:
cpu: "100m"
memory: "100Mi"
port: "7472"
version: v0.7.3

View File

@@ -0,0 +1,23 @@
---
- name: "Kubernetes Apps | Check cluster settings for MetalLB"
fail:
msg: "MetalLB require kube_proxy_strict_arp = true, see https://github.com/danderson/metallb/issues/153#issuecomment-518651132"
when:
- "kube_proxy_mode == 'ipvs' and not kube_proxy_strict_arp"
- name: "Kubernetes Apps | Lay Down MetalLB"
become: true
template: { src: "{{ item }}.j2", dest: "{{ kube_config_dir }}/{{ item }}" }
with_items: ["metallb.yml", "metallb-config.yml"]
register: "rendering"
when:
- "inventory_hostname == groups['kube-master'][0]"
- name: "Kubernetes Apps | Install and configure MetalLB"
kube:
name: "MetalLB"
kubectl: "{{ bin_dir }}/kubectl"
filename: "{{ kube_config_dir }}/{{ item.item }}"
state: "{{ item.changed | ternary('latest','present') }}"
become: true
with_items: "{{ rendering.results }}"
when:
- "inventory_hostname == groups['kube-master'][0]"

View File

@@ -0,0 +1,21 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: loadbalanced
protocol: {{ metallb.protocol }}
addresses:
- {{ metallb.ip_range }}
{% if metallb.additional_address_pools is defined %}{% for pool in metallb.additional_address_pools %}
- name: {{ pool }}
protocol: {{ metallb.additional_address_pools[pool].protocol }}
addresses:
- {{ metallb.additional_address_pools[pool].ip_range }}
auto-assign: {{ metallb.additional_address_pools[pool].auto_assign }}
{% endfor %}
{% endif %}

View File

@@ -0,0 +1,221 @@
apiVersion: v1
kind: Namespace
metadata:
name: metallb-system
labels:
app: metallb
---
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: metallb-system
name: controller
labels:
app: metallb
---
apiVersion: v1
kind: ServiceAccount
metadata:
namespace: metallb-system
name: speaker
labels:
app: metallb
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: metallb-system:controller
labels:
app: metallb
rules:
- apiGroups: [""]
resources: ["services"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: [""]
resources: ["services/status"]
verbs: ["update"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: metallb-system:speaker
labels:
app: metallb
rules:
- apiGroups: [""]
resources: ["services", "endpoints", "nodes"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: metallb-system
name: config-watcher
labels:
app: metallb
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create"]
---
## Role bindings
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: metallb-system:controller
labels:
app: metallb
subjects:
- kind: ServiceAccount
name: controller
namespace: metallb-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: metallb-system:controller
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: metallb-system:speaker
labels:
app: metallb
subjects:
- kind: ServiceAccount
name: speaker
namespace: metallb-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: metallb-system:speaker
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: metallb-system
name: config-watcher
labels:
app: metallb
subjects:
- kind: ServiceAccount
name: controller
- kind: ServiceAccount
name: speaker
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: config-watcher
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
namespace: metallb-system
name: speaker
labels:
app: metallb
component: speaker
spec:
selector:
matchLabels:
app: metallb
component: speaker
template:
metadata:
labels:
app: metallb
component: speaker
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "{{ metallb.port }}"
spec:
serviceAccountName: speaker
terminationGracePeriodSeconds: 0
hostNetwork: true
containers:
- name: speaker
image: metallb/speaker:{{ metallb.version }}
imagePullPolicy: IfNotPresent
args:
- --port={{ metallb.port }}
- --config=config
env:
- name: METALLB_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
ports:
- name: monitoring
containerPort: {{ metallb.port }}
resources:
limits:
cpu: {{ metallb.limits.cpu }}
memory: {{ metallb.limits.memory }}
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- all
add:
- net_raw
---
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: metallb-system
name: controller
labels:
app: metallb
component: controller
spec:
revisionHistoryLimit: 3
selector:
matchLabels:
app: metallb
component: controller
template:
metadata:
labels:
app: metallb
component: controller
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "{{ metallb.port }}"
spec:
serviceAccountName: controller
terminationGracePeriodSeconds: 0
securityContext:
runAsNonRoot: true
runAsUser: 65534 # nobody
containers:
- name: controller
image: metallb/controller:{{ metallb.version }}
imagePullPolicy: IfNotPresent
args:
- --port={{ metallb.port }}
- --config=config
ports:
- name: monitoring
containerPort: {{ metallb.port }}
resources:
limits:
cpu: {{ metallb.limits.cpu }}
memory: {{ metallb.limits.memory }}
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- all
readOnlyRootFilesystem: true
---

View File

@@ -1,5 +1,5 @@
--- ---
apiVersion: rbac.authorization.k8s.io/v1 apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding kind: ClusterRoleBinding
metadata: metadata:
name: kubernetes-dashboard name: kubernetes-dashboard

View File

@@ -8,19 +8,19 @@ In the same directory of this ReadMe file you should find a file named `inventor
Change that file to reflect your local setup (adding more machines or removing them and setting the adequate ip numbers), and save it to `inventory/sample/k8s_gfs_inventory`. Make sure that the settings on `inventory/sample/group_vars/all.yml` make sense with your deployment. Then execute change to the kubespray root folder, and execute (supposing that the machines are all using ubuntu): Change that file to reflect your local setup (adding more machines or removing them and setting the adequate ip numbers), and save it to `inventory/sample/k8s_gfs_inventory`. Make sure that the settings on `inventory/sample/group_vars/all.yml` make sense with your deployment. Then execute change to the kubespray root folder, and execute (supposing that the machines are all using ubuntu):
```shell ```
ansible-playbook -b --become-user=root -i inventory/sample/k8s_gfs_inventory --user=ubuntu ./cluster.yml ansible-playbook -b --become-user=root -i inventory/sample/k8s_gfs_inventory --user=ubuntu ./cluster.yml
``` ```
This will provision your Kubernetes cluster. Then, to provision and configure the GlusterFS cluster, from the same directory execute: This will provision your Kubernetes cluster. Then, to provision and configure the GlusterFS cluster, from the same directory execute:
```shell ```
ansible-playbook -b --become-user=root -i inventory/sample/k8s_gfs_inventory --user=ubuntu ./contrib/network-storage/glusterfs/glusterfs.yml ansible-playbook -b --become-user=root -i inventory/sample/k8s_gfs_inventory --user=ubuntu ./contrib/network-storage/glusterfs/glusterfs.yml
``` ```
If your machines are not using Ubuntu, you need to change the `--user=ubuntu` to the correct user. Alternatively, if your Kubernetes machines are using one OS and your GlusterFS a different one, you can instead specify the `ansible_ssh_user=<correct-user>` variable in the inventory file that you just created, for each machine/VM: If your machines are not using Ubuntu, you need to change the `--user=ubuntu` to the correct user. Alternatively, if your Kubernetes machines are using one OS and your GlusterFS a different one, you can instead specify the `ansible_ssh_user=<correct-user>` variable in the inventory file that you just created, for each machine/VM:
```shell ```
k8s-master-1 ansible_ssh_host=192.168.0.147 ip=192.168.0.147 ansible_ssh_user=core k8s-master-1 ansible_ssh_host=192.168.0.147 ip=192.168.0.147 ansible_ssh_user=core
k8s-master-node-1 ansible_ssh_host=192.168.0.148 ip=192.168.0.148 ansible_ssh_user=core k8s-master-node-1 ansible_ssh_host=192.168.0.148 ip=192.168.0.148 ansible_ssh_user=core
k8s-master-node-2 ansible_ssh_host=192.168.0.146 ip=192.168.0.146 ansible_ssh_user=core k8s-master-node-2 ansible_ssh_host=192.168.0.146 ip=192.168.0.146 ansible_ssh_user=core
@@ -30,7 +30,7 @@ k8s-master-node-2 ansible_ssh_host=192.168.0.146 ip=192.168.0.146 ansible_ssh_us
First step is to fill in a `my-kubespray-gluster-cluster.tfvars` file with the specification desired for your cluster. An example with all required variables would look like: First step is to fill in a `my-kubespray-gluster-cluster.tfvars` file with the specification desired for your cluster. An example with all required variables would look like:
```ini ```
cluster_name = "cluster1" cluster_name = "cluster1"
number_of_k8s_masters = "1" number_of_k8s_masters = "1"
number_of_k8s_masters_no_floating_ip = "2" number_of_k8s_masters_no_floating_ip = "2"
@@ -39,7 +39,7 @@ number_of_k8s_nodes = "0"
public_key_path = "~/.ssh/my-desired-key.pub" public_key_path = "~/.ssh/my-desired-key.pub"
image = "Ubuntu 16.04" image = "Ubuntu 16.04"
ssh_user = "ubuntu" ssh_user = "ubuntu"
flavor_k8s_node = "node-flavor-id-in-your-openstack" flavor_k8s_node = "node-flavor-id-in-your-openstack"
flavor_k8s_master = "master-flavor-id-in-your-openstack" flavor_k8s_master = "master-flavor-id-in-your-openstack"
network_name = "k8s-network" network_name = "k8s-network"
floatingip_pool = "net_external" floatingip_pool = "net_external"
@@ -54,7 +54,7 @@ ssh_user_gfs = "ubuntu"
As explained in the general terraform/openstack guide, you need to source your OpenStack credentials file, add your ssh-key to the ssh-agent and setup environment variables for terraform: As explained in the general terraform/openstack guide, you need to source your OpenStack credentials file, add your ssh-key to the ssh-agent and setup environment variables for terraform:
```shell ```
$ source ~/.stackrc $ source ~/.stackrc
$ eval $(ssh-agent -s) $ eval $(ssh-agent -s)
$ ssh-add ~/.ssh/my-desired-key $ ssh-add ~/.ssh/my-desired-key
@@ -67,7 +67,7 @@ $ echo Setting up Terraform creds && \
Then, standing on the kubespray directory (root base of the Git checkout), issue the following terraform command to create the VMs for the cluster: Then, standing on the kubespray directory (root base of the Git checkout), issue the following terraform command to create the VMs for the cluster:
```shell ```
terraform apply -state=contrib/terraform/openstack/terraform.tfstate -var-file=my-kubespray-gluster-cluster.tfvars contrib/terraform/openstack terraform apply -state=contrib/terraform/openstack/terraform.tfstate -var-file=my-kubespray-gluster-cluster.tfvars contrib/terraform/openstack
``` ```
@@ -75,18 +75,18 @@ This will create both your Kubernetes and Gluster VMs. Make sure that the ansibl
Then, provision your Kubernetes (kubespray) cluster with the following ansible call: Then, provision your Kubernetes (kubespray) cluster with the following ansible call:
```shell ```
ansible-playbook -b --become-user=root -i contrib/terraform/openstack/hosts ./cluster.yml ansible-playbook -b --become-user=root -i contrib/terraform/openstack/hosts ./cluster.yml
``` ```
Finally, provision the glusterfs nodes and add the Persistent Volume setup for GlusterFS in Kubernetes through the following ansible call: Finally, provision the glusterfs nodes and add the Persistent Volume setup for GlusterFS in Kubernetes through the following ansible call:
```shell ```
ansible-playbook -b --become-user=root -i contrib/terraform/openstack/hosts ./contrib/network-storage/glusterfs/glusterfs.yml ansible-playbook -b --become-user=root -i contrib/terraform/openstack/hosts ./contrib/network-storage/glusterfs/glusterfs.yml
``` ```
If you need to destroy the cluster, you can run: If you need to destroy the cluster, you can run:
```shell ```
terraform destroy -state=contrib/terraform/openstack/terraform.tfstate -var-file=my-kubespray-gluster-cluster.tfvars contrib/terraform/openstack terraform destroy -state=contrib/terraform/openstack/terraform.tfstate -var-file=my-kubespray-gluster-cluster.tfvars contrib/terraform/openstack
``` ```

View File

@@ -7,7 +7,7 @@
register: glusterfs_ppa_added register: glusterfs_ppa_added
when: glusterfs_ppa_use when: glusterfs_ppa_use
- name: Ensure GlusterFS client will reinstall if the PPA was just added. # noqa 503 - name: Ensure GlusterFS client will reinstall if the PPA was just added.
apt: apt:
name: "{{ item }}" name: "{{ item }}"
state: absent state: absent
@@ -18,7 +18,7 @@
- name: Ensure GlusterFS client is installed. - name: Ensure GlusterFS client is installed.
apt: apt:
name: "{{ item }}" name: "{{ item }}"
state: present state: installed
default_release: "{{ glusterfs_default_release }}" default_release: "{{ glusterfs_default_release }}"
with_items: with_items:
- glusterfs-client - glusterfs-client

View File

@@ -7,7 +7,7 @@
register: glusterfs_ppa_added register: glusterfs_ppa_added
when: glusterfs_ppa_use when: glusterfs_ppa_use
- name: Ensure GlusterFS will reinstall if the PPA was just added. # noqa 503 - name: Ensure GlusterFS will reinstall if the PPA was just added.
apt: apt:
name: "{{ item }}" name: "{{ item }}"
state: absent state: absent
@@ -19,7 +19,7 @@
- name: Ensure GlusterFS is installed. - name: Ensure GlusterFS is installed.
apt: apt:
name: "{{ item }}" name: "{{ item }}"
state: present state: installed
default_release: "{{ glusterfs_default_release }}" default_release: "{{ glusterfs_default_release }}"
with_items: with_items:
- glusterfs-server - glusterfs-server

View File

@@ -8,7 +8,7 @@
{% for host in groups['gfs-cluster'] %} {% for host in groups['gfs-cluster'] %}
{ {
"addresses": [ "addresses": [
{ {
"ip": "{{hostvars[host]['ip']|default(hostvars[host].ansible_default_ipv4['address'])}}" "ip": "{{hostvars[host]['ip']|default(hostvars[host].ansible_default_ipv4['address'])}}"
} }
], ],

View File

@@ -1,7 +1,7 @@
apiVersion: v1 apiVersion: v1
kind: PersistentVolume kind: PersistentVolume
metadata: metadata:
name: glusterfs name: glusterfs
spec: spec:
capacity: capacity:
storage: "{{ hostvars[groups['gfs-cluster'][0]].gluster_disk_size_gb }}Gi" storage: "{{ hostvars[groups['gfs-cluster'][0]].gluster_disk_size_gb }}Gi"

View File

@@ -1,26 +1,17 @@
# Deploy Heketi/Glusterfs into Kubespray/Kubernetes # Deploy Heketi/Glusterfs into Kubespray/Kubernetes
This playbook aims to automate [this](https://github.com/heketi/heketi/blob/master/docs/admin/install-kubernetes.md) tutorial. It deploys heketi/glusterfs into kubernetes and sets up a storageclass. This playbook aims to automate [this](https://github.com/heketi/heketi/blob/master/docs/admin/install-kubernetes.md) tutorial. It deploys heketi/glusterfs into kubernetes and sets up a storageclass.
## Important notice
> Due to resource limits on the current project maintainers and general lack of contributions we are considering placing Heketi into a [near-maintenance mode](https://github.com/heketi/heketi#important-notice)
## Client Setup ## Client Setup
Heketi provides a CLI that provides users with a means to administer the deployment and configuration of GlusterFS in Kubernetes. [Download and install the heketi-cli](https://github.com/heketi/heketi/releases) on your client machine. Heketi provides a CLI that provides users with a means to administer the deployment and configuration of GlusterFS in Kubernetes. [Download and install the heketi-cli](https://github.com/heketi/heketi/releases) on your client machine.
## Install ## Install
Copy the inventory.yml.sample over to inventory/sample/k8s_heketi_inventory.yml and change it according to your setup. Copy the inventory.yml.sample over to inventory/sample/k8s_heketi_inventory.yml and change it according to your setup.
```
```shell
ansible-playbook --ask-become -i inventory/sample/k8s_heketi_inventory.yml contrib/network-storage/heketi/heketi.yml ansible-playbook --ask-become -i inventory/sample/k8s_heketi_inventory.yml contrib/network-storage/heketi/heketi.yml
``` ```
## Tear down ## Tear down
```
```shell
ansible-playbook --ask-become -i inventory/sample/k8s_heketi_inventory.yml contrib/network-storage/heketi/heketi-tear-down.yml ansible-playbook --ask-become -i inventory/sample/k8s_heketi_inventory.yml contrib/network-storage/heketi/heketi-tear-down.yml
``` ```

View File

@@ -6,7 +6,7 @@
- name: "Delete bootstrap Heketi." - name: "Delete bootstrap Heketi."
command: "{{ bin_dir }}/kubectl delete all,service,jobs,deployment,secret --selector=\"deploy-heketi\"" command: "{{ bin_dir }}/kubectl delete all,service,jobs,deployment,secret --selector=\"deploy-heketi\""
when: "heketi_resources.stdout|from_json|json_query('items[*]')|length > 0" when: "heketi_resources.stdout|from_json|json_query('items[*]')|length > 0"
- name: "Ensure there is nothing left over." # noqa 301 - name: "Ensure there is nothing left over."
command: "{{ bin_dir }}/kubectl get all,service,jobs,deployment,secret --selector=\"deploy-heketi\" -o=json" command: "{{ bin_dir }}/kubectl get all,service,jobs,deployment,secret --selector=\"deploy-heketi\" -o=json"
register: "heketi_result" register: "heketi_result"
until: "heketi_result.stdout|from_json|json_query('items[*]')|length == 0" until: "heketi_result.stdout|from_json|json_query('items[*]')|length == 0"

View File

@@ -13,7 +13,7 @@
- name: "Copy topology configuration into container." - name: "Copy topology configuration into container."
changed_when: false changed_when: false
command: "{{ bin_dir }}/kubectl cp {{ kube_config_dir }}/topology.json {{ initial_heketi_pod_name }}:/tmp/topology.json" command: "{{ bin_dir }}/kubectl cp {{ kube_config_dir }}/topology.json {{ initial_heketi_pod_name }}:/tmp/topology.json"
- name: "Load heketi topology." # noqa 503 - name: "Load heketi topology."
when: "render.changed" when: "render.changed"
command: "{{ bin_dir }}/kubectl exec {{ initial_heketi_pod_name }} -- heketi-cli --user admin --secret {{ heketi_admin_key }} topology load --json=/tmp/topology.json" command: "{{ bin_dir }}/kubectl exec {{ initial_heketi_pod_name }} -- heketi-cli --user admin --secret {{ heketi_admin_key }} topology load --json=/tmp/topology.json"
register: "load_heketi" register: "load_heketi"

View File

@@ -18,7 +18,7 @@
- name: "Provision database volume." - name: "Provision database volume."
command: "{{ bin_dir }}/kubectl exec {{ initial_heketi_pod_name }} -- heketi-cli --user admin --secret {{ heketi_admin_key }} setup-openshift-heketi-storage" command: "{{ bin_dir }}/kubectl exec {{ initial_heketi_pod_name }} -- heketi-cli --user admin --secret {{ heketi_admin_key }} setup-openshift-heketi-storage"
when: "heketi_database_volume_exists is undefined" when: "heketi_database_volume_exists is undefined"
- name: "Copy configuration from pod." # noqa 301 - name: "Copy configuration from pod."
become: true become: true
command: "{{ bin_dir }}/kubectl cp {{ initial_heketi_pod_name }}:/heketi-storage.json {{ kube_config_dir }}/heketi-storage-bootstrap.json" command: "{{ bin_dir }}/kubectl cp {{ initial_heketi_pod_name }}:/heketi-storage.json {{ kube_config_dir }}/heketi-storage-bootstrap.json"
- name: "Get heketi volume ids." - name: "Get heketi volume ids."

View File

@@ -10,10 +10,10 @@
template: template:
src: "topology.json.j2" src: "topology.json.j2"
dest: "{{ kube_config_dir }}/topology.json" dest: "{{ kube_config_dir }}/topology.json"
- name: "Copy topology configuration into container." # noqa 503 - name: "Copy topology configuration into container."
when: "rendering.changed" when: "rendering.changed"
command: "{{ bin_dir }}/kubectl cp {{ kube_config_dir }}/topology.json {{ heketi_pod_name }}:/tmp/topology.json" command: "{{ bin_dir }}/kubectl cp {{ kube_config_dir }}/topology.json {{ heketi_pod_name }}:/tmp/topology.json"
- name: "Load heketi topology." # noqa 503 - name: "Load heketi topology."
when: "rendering.changed" when: "rendering.changed"
command: "{{ bin_dir }}/kubectl exec {{ heketi_pod_name }} -- heketi-cli --user admin --secret {{ heketi_admin_key }} topology load --json=/tmp/topology.json" command: "{{ bin_dir }}/kubectl exec {{ heketi_pod_name }} -- heketi-cli --user admin --secret {{ heketi_admin_key }} topology load --json=/tmp/topology.json"
- name: "Get heketi topology." - name: "Get heketi topology."

View File

@@ -12,11 +12,6 @@
} }
}, },
"spec": { "spec": {
"selector": {
"matchLabels": {
"glusterfs-node": "daemonset"
}
},
"template": { "template": {
"metadata": { "metadata": {
"name": "glusterfs", "name": "glusterfs",

View File

@@ -42,11 +42,6 @@
} }
}, },
"spec": { "spec": {
"selector": {
"matchLabels": {
"name": "deploy-heketi"
}
},
"replicas": 1, "replicas": 1,
"template": { "template": {
"metadata": { "metadata": {

View File

@@ -55,11 +55,6 @@
} }
}, },
"spec": { "spec": {
"selector": {
"matchLabels": {
"name": "heketi"
}
},
"replicas": 1, "replicas": 1,
"template": { "template": {
"metadata": { "metadata": {

View File

@@ -22,7 +22,7 @@
ignore_errors: true ignore_errors: true
changed_when: false changed_when: false
- name: "Remove volume groups." # noqa 301 - name: "Remove volume groups."
environment: environment:
PATH: "{{ ansible_env.PATH }}:/sbin" # Make sure we can workaround RH / CentOS conservative path management PATH: "{{ ansible_env.PATH }}:/sbin" # Make sure we can workaround RH / CentOS conservative path management
become: true become: true
@@ -30,7 +30,7 @@
with_items: "{{ volume_groups.stdout_lines }}" with_items: "{{ volume_groups.stdout_lines }}"
loop_control: { loop_var: "volume_group" } loop_control: { loop_var: "volume_group" }
- name: "Remove physical volume from cluster disks." # noqa 301 - name: "Remove physical volume from cluster disks."
environment: environment:
PATH: "{{ ansible_env.PATH }}:/sbin" # Make sure we can workaround RH / CentOS conservative path management PATH: "{{ ansible_env.PATH }}:/sbin" # Make sure we can workaround RH / CentOS conservative path management
become: true become: true

View File

@@ -1,43 +1,43 @@
--- ---
- name: "Remove storage class." # noqa 301 - name: "Remove storage class."
command: "{{ bin_dir }}/kubectl delete storageclass gluster" command: "{{ bin_dir }}/kubectl delete storageclass gluster"
ignore_errors: true ignore_errors: true
- name: "Tear down heketi." # noqa 301 - name: "Tear down heketi."
command: "{{ bin_dir }}/kubectl delete all,service,jobs,deployment,secret --selector=\"glusterfs=heketi-pod\"" command: "{{ bin_dir }}/kubectl delete all,service,jobs,deployment,secret --selector=\"glusterfs=heketi-pod\""
ignore_errors: true ignore_errors: true
- name: "Tear down heketi." # noqa 301 - name: "Tear down heketi."
command: "{{ bin_dir }}/kubectl delete all,service,jobs,deployment,secret --selector=\"glusterfs=heketi-deployment\"" command: "{{ bin_dir }}/kubectl delete all,service,jobs,deployment,secret --selector=\"glusterfs=heketi-deployment\""
ignore_errors: true ignore_errors: true
- name: "Tear down bootstrap." - name: "Tear down bootstrap."
include_tasks: "../../provision/tasks/bootstrap/tear-down.yml" include_tasks: "../provision/tasks/bootstrap/tear-down.yml"
- name: "Ensure there is nothing left over." # noqa 301 - name: "Ensure there is nothing left over."
command: "{{ bin_dir }}/kubectl get all,service,jobs,deployment,secret --selector=\"glusterfs=heketi-pod\" -o=json" command: "{{ bin_dir }}/kubectl get all,service,jobs,deployment,secret --selector=\"glusterfs=heketi-pod\" -o=json"
register: "heketi_result" register: "heketi_result"
until: "heketi_result.stdout|from_json|json_query('items[*]')|length == 0" until: "heketi_result.stdout|from_json|json_query('items[*]')|length == 0"
retries: 60 retries: 60
delay: 5 delay: 5
- name: "Ensure there is nothing left over." # noqa 301 - name: "Ensure there is nothing left over."
command: "{{ bin_dir }}/kubectl get all,service,jobs,deployment,secret --selector=\"glusterfs=heketi-deployment\" -o=json" command: "{{ bin_dir }}/kubectl get all,service,jobs,deployment,secret --selector=\"glusterfs=heketi-deployment\" -o=json"
register: "heketi_result" register: "heketi_result"
until: "heketi_result.stdout|from_json|json_query('items[*]')|length == 0" until: "heketi_result.stdout|from_json|json_query('items[*]')|length == 0"
retries: 60 retries: 60
delay: 5 delay: 5
- name: "Tear down glusterfs." # noqa 301 - name: "Tear down glusterfs."
command: "{{ bin_dir }}/kubectl delete daemonset.extensions/glusterfs" command: "{{ bin_dir }}/kubectl delete daemonset.extensions/glusterfs"
ignore_errors: true ignore_errors: true
- name: "Remove heketi storage service." # noqa 301 - name: "Remove heketi storage service."
command: "{{ bin_dir }}/kubectl delete service heketi-storage-endpoints" command: "{{ bin_dir }}/kubectl delete service heketi-storage-endpoints"
ignore_errors: true ignore_errors: true
- name: "Remove heketi gluster role binding" # noqa 301 - name: "Remove heketi gluster role binding"
command: "{{ bin_dir }}/kubectl delete clusterrolebinding heketi-gluster-admin" command: "{{ bin_dir }}/kubectl delete clusterrolebinding heketi-gluster-admin"
ignore_errors: true ignore_errors: true
- name: "Remove heketi config secret" # noqa 301 - name: "Remove heketi config secret"
command: "{{ bin_dir }}/kubectl delete secret heketi-config-secret" command: "{{ bin_dir }}/kubectl delete secret heketi-config-secret"
ignore_errors: true ignore_errors: true
- name: "Remove heketi db backup" # noqa 301 - name: "Remove heketi db backup"
command: "{{ bin_dir }}/kubectl delete secret heketi-db-backup" command: "{{ bin_dir }}/kubectl delete secret heketi-db-backup"
ignore_errors: true ignore_errors: true
- name: "Remove heketi service account" # noqa 301 - name: "Remove heketi service account"
command: "{{ bin_dir }}/kubectl delete serviceaccount heketi-service-account" command: "{{ bin_dir }}/kubectl delete serviceaccount heketi-service-account"
ignore_errors: true ignore_errors: true
- name: "Get secrets" - name: "Get secrets"

View File

@@ -1,21 +0,0 @@
# Container image collecting script for offline deployment
This script has two features:
(1) Get container images from an environment which is deployed online.
(2) Deploy local container registry and register the container images to the registry.
Step(1) should be done online site as a preparation, then we bring the gotten images
to the target offline environment.
Then we will run step(2) for registering the images to local registry.
Step(1) can be operated with:
```shell
manage-offline-container-images.sh create
```
Step(2) can be operated with:
```shell
manage-offline-container-images.sh register
```

View File

@@ -1 +0,0 @@
{ "insecure-registries":["HOSTNAME:5000"] }

View File

@@ -1,150 +0,0 @@
#!/bin/bash
OPTION=$1
CURRENT_DIR=$(cd $(dirname $0); pwd)
TEMP_DIR="${CURRENT_DIR}/temp"
IMAGE_TAR_FILE="${CURRENT_DIR}/container-images.tar.gz"
IMAGE_DIR="${CURRENT_DIR}/container-images"
IMAGE_LIST="${IMAGE_DIR}/container-images.txt"
RETRY_COUNT=5
function create_container_image_tar() {
set -e
IMAGES=$(kubectl describe pods --all-namespaces | grep " Image:" | awk '{print $2}' | sort | uniq)
# NOTE: etcd and pause cannot be seen as pods.
# The pause image is used for --pod-infra-container-image option of kubelet.
EXT_IMAGES=$(kubectl cluster-info dump | egrep "quay.io/coreos/etcd:|k8s.gcr.io/pause:" | sed s@\"@@g)
IMAGES="${IMAGES} ${EXT_IMAGES}"
rm -f ${IMAGE_TAR_FILE}
rm -rf ${IMAGE_DIR}
mkdir ${IMAGE_DIR}
cd ${IMAGE_DIR}
sudo docker pull registry:latest
sudo docker save -o registry-latest.tar registry:latest
for image in ${IMAGES}
do
FILE_NAME="$(echo ${image} | sed s@"/"@"-"@g | sed s/":"/"-"/g)".tar
set +e
for step in $(seq 1 ${RETRY_COUNT})
do
sudo docker pull ${image}
if [ $? -eq 0 ]; then
break
fi
echo "Failed to pull ${image} at step ${step}"
if [ ${step} -eq ${RETRY_COUNT} ]; then
exit 1
fi
done
set -e
sudo docker save -o ${FILE_NAME} ${image}
# NOTE: Here removes the following repo parts from each image
# so that these parts will be replaced with Kubespray.
# - kube_image_repo: "k8s.gcr.io"
# - gcr_image_repo: "gcr.io"
# - docker_image_repo: "docker.io"
# - quay_image_repo: "quay.io"
FIRST_PART=$(echo ${image} | awk -F"/" '{print $1}')
if [ "${FIRST_PART}" = "k8s.gcr.io" ] ||
[ "${FIRST_PART}" = "gcr.io" ] ||
[ "${FIRST_PART}" = "docker.io" ] ||
[ "${FIRST_PART}" = "quay.io" ]; then
image=$(echo ${image} | sed s@"${FIRST_PART}/"@@)
fi
echo "${FILE_NAME} ${image}" >> ${IMAGE_LIST}
done
cd ..
sudo chown ${USER} ${IMAGE_DIR}/*
tar -zcvf ${IMAGE_TAR_FILE} ./container-images
rm -rf ${IMAGE_DIR}
echo ""
echo "${IMAGE_TAR_FILE} is created to contain your container images."
echo "Please keep this file and bring it to your offline environment."
}
function register_container_images() {
if [ ! -f ${IMAGE_TAR_FILE} ]; then
echo "${IMAGE_TAR_FILE} should exist."
exit 1
fi
if [ ! -d ${TEMP_DIR} ]; then
mkdir ${TEMP_DIR}
fi
# To avoid "http: server gave http response to https client" error.
LOCALHOST_NAME=$(hostname)
if [ -d /etc/docker/ ]; then
set -e
# Ubuntu18.04, RHEL7/CentOS7
cp ${CURRENT_DIR}/docker-daemon.json ${TEMP_DIR}/docker-daemon.json
sed -i s@"HOSTNAME"@"${LOCALHOST_NAME}"@ ${TEMP_DIR}/docker-daemon.json
sudo cp ${TEMP_DIR}/docker-daemon.json /etc/docker/daemon.json
elif [ -d /etc/containers/ ]; then
set -e
# RHEL8/CentOS8
cp ${CURRENT_DIR}/registries.conf ${TEMP_DIR}/registries.conf
sed -i s@"HOSTNAME"@"${LOCALHOST_NAME}"@ ${TEMP_DIR}/registries.conf
sudo cp ${TEMP_DIR}/registries.conf /etc/containers/registries.conf
else
echo "docker package(docker-ce, etc.) should be installed"
exit 1
fi
tar -zxvf ${IMAGE_TAR_FILE}
sudo docker load -i ${IMAGE_DIR}/registry-latest.tar
sudo docker run --restart=always -d -p 5000:5000 --name registry registry:latest
set +e
set -e
while read -r line; do
file_name=$(echo ${line} | awk '{print $1}')
org_image=$(echo ${line} | awk '{print $2}')
new_image="${LOCALHOST_NAME}:5000/${org_image}"
image_id=$(tar -tf ${IMAGE_DIR}/${file_name} | grep "\.json" | grep -v manifest.json | sed s/"\.json"//)
sudo docker load -i ${IMAGE_DIR}/${file_name}
sudo docker tag ${image_id} ${new_image}
sudo docker push ${new_image}
done <<< "$(cat ${IMAGE_LIST})"
echo "Succeeded to register container images to local registry."
echo "Please specify ${LOCALHOST_NAME}:5000 for the following options in your inventry:"
echo "- kube_image_repo"
echo "- gcr_image_repo"
echo "- docker_image_repo"
echo "- quay_image_repo"
}
if [ "${OPTION}" == "create" ]; then
create_container_image_tar
elif [ "${OPTION}" == "register" ]; then
register_container_images
else
echo "This script has two features:"
echo "(1) Get container images from an environment which is deployed online."
echo "(2) Deploy local container registry and register the container images to the registry."
echo ""
echo "Step(1) should be done online site as a preparation, then we bring"
echo "the gotten images to the target offline environment."
echo "Then we will run step(2) for registering the images to local registry."
echo ""
echo "${IMAGE_TAR_FILE} is created to contain your container images."
echo "Please keep this file and bring it to your offline environment."
echo ""
echo "Step(1) can be operated with:"
echo " $ ./manage-offline-container-images.sh create"
echo ""
echo "Step(2) can be operated with:"
echo " $ ./manage-offline-container-images.sh register"
echo ""
echo "Please specify 'create' or 'register'."
echo ""
exit 1
fi

View File

@@ -1,8 +0,0 @@
[registries.search]
registries = ['registry.access.redhat.com', 'registry.redhat.io', 'docker.io']
[registries.insecure]
registries = ['HOSTNAME:5000']
[registries.block]
registries = []

View File

@@ -1,64 +1,55 @@
# Kubernetes on AWS with Terraform ## Kubernetes on AWS with Terraform
## Overview **Overview:**
This project will create: This project will create:
* VPC with Public and Private Subnets in # Availability Zones
* Bastion Hosts and NAT Gateways in the Public Subnet
* A dynamic number of masters, etcd, and worker nodes in the Private Subnet
* even distributed over the # of Availability Zones
* AWS ELB in the Public Subnet for accessing the Kubernetes API from the internet
- VPC with Public and Private Subnets in # Availability Zones **Requirements**
- Bastion Hosts and NAT Gateways in the Public Subnet
- A dynamic number of masters, etcd, and worker nodes in the Private Subnet
- even distributed over the # of Availability Zones
- AWS ELB in the Public Subnet for accessing the Kubernetes API from the internet
## Requirements
- Terraform 0.12.0 or newer - Terraform 0.12.0 or newer
## How to Use **How to Use:**
- Export the variables for your AWS credentials or edit `credentials.tfvars`: - Export the variables for your AWS credentials or edit `credentials.tfvars`:
```commandline ```
export TF_VAR_AWS_ACCESS_KEY_ID="www" export TF_VAR_AWS_ACCESS_KEY_ID="www"
export TF_VAR_AWS_SECRET_ACCESS_KEY ="xxx" export TF_VAR_AWS_SECRET_ACCESS_KEY ="xxx"
export TF_VAR_AWS_SSH_KEY_NAME="yyy" export TF_VAR_AWS_SSH_KEY_NAME="yyy"
export TF_VAR_AWS_DEFAULT_REGION="zzz" export TF_VAR_AWS_DEFAULT_REGION="zzz"
``` ```
- Update `contrib/terraform/aws/terraform.tfvars` with your data. By default, the Terraform scripts use CoreOS as base image. If you want to change this behaviour, see note "Using other distrib than CoreOs" below.
- Update `contrib/terraform/aws/terraform.tfvars` with your data. By default, the Terraform scripts use Ubuntu 18.04 LTS (Bionic) as base image. If you want to change this behaviour, see note "Using other distrib than Ubuntu" below.
- Create an AWS EC2 SSH Key - Create an AWS EC2 SSH Key
- Run with `terraform apply --var-file="credentials.tfvars"` or `terraform apply` depending if you exported your AWS credentials - Run with `terraform apply --var-file="credentials.tfvars"` or `terraform apply` depending if you exported your AWS credentials
Example: Example:
```commandline ```commandline
terraform apply -var-file=credentials.tfvars terraform apply -var-file=credentials.tfvars
``` ```
- Terraform automatically creates an Ansible Inventory file called `hosts` with the created infrastructure in the directory `inventory` - Terraform automatically creates an Ansible Inventory file called `hosts` with the created infrastructure in the directory `inventory`
- Ansible will automatically generate an ssh config file for your bastion hosts. To connect to hosts with ssh using bastion host use generated ssh-bastion.conf. - Ansible will automatically generate an ssh config file for your bastion hosts. To connect to hosts with ssh using bastion host use generated ssh-bastion.conf.
Ansible automatically detects bastion and changes ssh_args Ansible automatically detects bastion and changes ssh_args
```commandline ```commandline
ssh -F ./ssh-bastion.conf user@$ip ssh -F ./ssh-bastion.conf user@$ip
``` ```
- Once the infrastructure is created, you can run the kubespray playbooks and supply inventory/hosts with the `-i` flag. - Once the infrastructure is created, you can run the kubespray playbooks and supply inventory/hosts with the `-i` flag.
Example (this one assumes you are using Ubuntu) Example (this one assumes you are using CoreOS)
```commandline ```commandline
ansible-playbook -i ./inventory/hosts ./cluster.yml -e ansible_user=ubuntu -b --become-user=root --flush-cache ansible-playbook -i ./inventory/hosts ./cluster.yml -e ansible_user=core -b --become-user=root --flush-cache
``` ```
***Using other distrib than CoreOs***
***Using other distrib than Ubuntu*** If you want to use another distribution than CoreOS, you can modify the search filters of the 'data "aws_ami" "distro"' in variables.tf.
If you want to use another distribution than Ubuntu 18.04 (Bionic) LTS, you can modify the search filters of the 'data "aws_ami" "distro"' in variables.tf.
For example, to use: For example, to use:
- Debian Jessie, replace 'data "aws_ami" "distro"' in variables.tf with - Debian Jessie, replace 'data "aws_ami" "distro"' in variables.tf with
```ini
data "aws_ami" "distro" { data "aws_ami" "distro" {
most_recent = true most_recent = true
@@ -74,11 +65,8 @@ data "aws_ami" "distro" {
owners = ["379101102735"] owners = ["379101102735"]
} }
```
- Ubuntu 16.04, replace 'data "aws_ami" "distro"' in variables.tf with - Ubuntu 16.04, replace 'data "aws_ami" "distro"' in variables.tf with
```ini
data "aws_ami" "distro" { data "aws_ami" "distro" {
most_recent = true most_recent = true
@@ -94,11 +82,8 @@ data "aws_ami" "distro" {
owners = ["099720109477"] owners = ["099720109477"]
} }
```
- Centos 7, replace 'data "aws_ami" "distro"' in variables.tf with - Centos 7, replace 'data "aws_ami" "distro"' in variables.tf with
```ini
data "aws_ami" "distro" { data "aws_ami" "distro" {
most_recent = true most_recent = true
@@ -114,49 +99,23 @@ data "aws_ami" "distro" {
owners = ["688023202711"] owners = ["688023202711"]
} }
```
## Connecting to Kubernetes **Troubleshooting**
You can use the following set of commands to get the kubeconfig file from your newly created cluster. Before running the commands, make sure you are in the project's root folder. ***Remaining AWS IAM Instance Profile***:
```commandline
# Get the controller's IP address.
CONTROLLER_HOST_NAME=$(cat ./inventory/hosts | grep "\[kube-master\]" -A 1 | tail -n 1)
CONTROLLER_IP=$(cat ./inventory/hosts | grep $CONTROLLER_HOST_NAME | grep ansible_host | cut -d'=' -f2)
# Get the hostname of the load balancer.
LB_HOST=$(cat inventory/hosts | grep apiserver_loadbalancer_domain_name | cut -d'"' -f2)
# Get the controller's SSH fingerprint.
ssh-keygen -R $CONTROLLER_IP > /dev/null 2>&1
ssh-keyscan -H $CONTROLLER_IP >> ~/.ssh/known_hosts 2>/dev/null
# Get the kubeconfig from the controller.
mkdir -p ~/.kube
ssh -F ssh-bastion.conf centos@$CONTROLLER_IP "sudo chmod 644 /etc/kubernetes/admin.conf"
scp -F ssh-bastion.conf centos@$CONTROLLER_IP:/etc/kubernetes/admin.conf ~/.kube/config
sed -i "s^server:.*^server: https://$LB_HOST:6443^" ~/.kube/config
kubectl get nodes
```
## Troubleshooting
### Remaining AWS IAM Instance Profile
If the cluster was destroyed without using Terraform it is possible that If the cluster was destroyed without using Terraform it is possible that
the AWS IAM Instance Profiles still remain. To delete them you can use the AWS IAM Instance Profiles still remain. To delete them you can use
the `AWS CLI` with the following command: the `AWS CLI` with the following command:
```
```commandline
aws iam delete-instance-profile --region <region_name> --instance-profile-name <profile_name> aws iam delete-instance-profile --region <region_name> --instance-profile-name <profile_name>
``` ```
### Ansible Inventory doesn't get created ***Ansible Inventory doesn't get created:***
It could happen that Terraform doesn't create an Ansible Inventory file automatically. If this is the case copy the output after `inventory=` and create a file named `hosts`in the directory `inventory` and paste the inventory into the file. It could happen that Terraform doesn't create an Ansible Inventory file automatically. If this is the case copy the output after `inventory=` and create a file named `hosts`in the directory `inventory` and paste the inventory into the file.
## Architecture **Architecture**
Pictured is an AWS Infrastructure created with this Terraform project distributed over two Availability Zones. Pictured is an AWS Infrastructure created with this Terraform project distributed over two Availability Zones.

View File

@@ -3,9 +3,9 @@ terraform {
} }
provider "aws" { provider "aws" {
access_key = var.AWS_ACCESS_KEY_ID access_key = "${var.AWS_ACCESS_KEY_ID}"
secret_key = var.AWS_SECRET_ACCESS_KEY secret_key = "${var.AWS_SECRET_ACCESS_KEY}"
region = var.AWS_DEFAULT_REGION region = "${var.AWS_DEFAULT_REGION}"
} }
data "aws_availability_zones" "available" {} data "aws_availability_zones" "available" {}
@@ -18,30 +18,30 @@ data "aws_availability_zones" "available" {}
module "aws-vpc" { module "aws-vpc" {
source = "./modules/vpc" source = "./modules/vpc"
aws_cluster_name = var.aws_cluster_name aws_cluster_name = "${var.aws_cluster_name}"
aws_vpc_cidr_block = var.aws_vpc_cidr_block aws_vpc_cidr_block = "${var.aws_vpc_cidr_block}"
aws_avail_zones = slice(data.aws_availability_zones.available.names, 0, 2) aws_avail_zones = "${slice(data.aws_availability_zones.available.names, 0, 2)}"
aws_cidr_subnets_private = var.aws_cidr_subnets_private aws_cidr_subnets_private = "${var.aws_cidr_subnets_private}"
aws_cidr_subnets_public = var.aws_cidr_subnets_public aws_cidr_subnets_public = "${var.aws_cidr_subnets_public}"
default_tags = var.default_tags default_tags = "${var.default_tags}"
} }
module "aws-elb" { module "aws-elb" {
source = "./modules/elb" source = "./modules/elb"
aws_cluster_name = var.aws_cluster_name aws_cluster_name = "${var.aws_cluster_name}"
aws_vpc_id = module.aws-vpc.aws_vpc_id aws_vpc_id = "${module.aws-vpc.aws_vpc_id}"
aws_avail_zones = slice(data.aws_availability_zones.available.names, 0, 2) aws_avail_zones = "${slice(data.aws_availability_zones.available.names, 0, 2)}"
aws_subnet_ids_public = module.aws-vpc.aws_subnet_ids_public aws_subnet_ids_public = "${module.aws-vpc.aws_subnet_ids_public}"
aws_elb_api_port = var.aws_elb_api_port aws_elb_api_port = "${var.aws_elb_api_port}"
k8s_secure_api_port = var.k8s_secure_api_port k8s_secure_api_port = "${var.k8s_secure_api_port}"
default_tags = var.default_tags default_tags = "${var.default_tags}"
} }
module "aws-iam" { module "aws-iam" {
source = "./modules/iam" source = "./modules/iam"
aws_cluster_name = var.aws_cluster_name aws_cluster_name = "${var.aws_cluster_name}"
} }
/* /*
@@ -50,22 +50,22 @@ module "aws-iam" {
*/ */
resource "aws_instance" "bastion-server" { resource "aws_instance" "bastion-server" {
ami = data.aws_ami.distro.id ami = "${data.aws_ami.distro.id}"
instance_type = var.aws_bastion_size instance_type = "${var.aws_bastion_size}"
count = length(var.aws_cidr_subnets_public) count = "${length(var.aws_cidr_subnets_public)}"
associate_public_ip_address = true associate_public_ip_address = true
availability_zone = element(slice(data.aws_availability_zones.available.names, 0, 2), count.index) availability_zone = "${element(slice(data.aws_availability_zones.available.names, 0, 2), count.index)}"
subnet_id = element(module.aws-vpc.aws_subnet_ids_public, count.index) subnet_id = "${element(module.aws-vpc.aws_subnet_ids_public, count.index)}"
vpc_security_group_ids = module.aws-vpc.aws_security_group vpc_security_group_ids = "${module.aws-vpc.aws_security_group}"
key_name = var.AWS_SSH_KEY_NAME key_name = "${var.AWS_SSH_KEY_NAME}"
tags = merge(var.default_tags, map( tags = "${merge(var.default_tags, map(
"Name", "kubernetes-${var.aws_cluster_name}-bastion-${count.index}", "Name", "kubernetes-${var.aws_cluster_name}-bastion-${count.index}",
"Cluster", var.aws_cluster_name, "Cluster", "${var.aws_cluster_name}",
"Role", "bastion-${var.aws_cluster_name}-${count.index}" "Role", "bastion-${var.aws_cluster_name}-${count.index}"
)) ))}"
} }
/* /*
@@ -74,71 +74,71 @@ resource "aws_instance" "bastion-server" {
*/ */
resource "aws_instance" "k8s-master" { resource "aws_instance" "k8s-master" {
ami = data.aws_ami.distro.id ami = "${data.aws_ami.distro.id}"
instance_type = var.aws_kube_master_size instance_type = "${var.aws_kube_master_size}"
count = var.aws_kube_master_num count = "${var.aws_kube_master_num}"
availability_zone = element(slice(data.aws_availability_zones.available.names, 0, 2), count.index) availability_zone = "${element(slice(data.aws_availability_zones.available.names, 0, 2), count.index)}"
subnet_id = element(module.aws-vpc.aws_subnet_ids_private, count.index) subnet_id = "${element(module.aws-vpc.aws_subnet_ids_private, count.index)}"
vpc_security_group_ids = module.aws-vpc.aws_security_group vpc_security_group_ids = "${module.aws-vpc.aws_security_group}"
iam_instance_profile = module.aws-iam.kube-master-profile iam_instance_profile = "${module.aws-iam.kube-master-profile}"
key_name = var.AWS_SSH_KEY_NAME key_name = "${var.AWS_SSH_KEY_NAME}"
tags = merge(var.default_tags, map( tags = "${merge(var.default_tags, map(
"Name", "kubernetes-${var.aws_cluster_name}-master${count.index}", "Name", "kubernetes-${var.aws_cluster_name}-master${count.index}",
"kubernetes.io/cluster/${var.aws_cluster_name}", "member", "kubernetes.io/cluster/${var.aws_cluster_name}", "member",
"Role", "master" "Role", "master"
)) ))}"
} }
resource "aws_elb_attachment" "attach_master_nodes" { resource "aws_elb_attachment" "attach_master_nodes" {
count = var.aws_kube_master_num count = "${var.aws_kube_master_num}"
elb = module.aws-elb.aws_elb_api_id elb = "${module.aws-elb.aws_elb_api_id}"
instance = element(aws_instance.k8s-master.*.id, count.index) instance = "${element(aws_instance.k8s-master.*.id, count.index)}"
} }
resource "aws_instance" "k8s-etcd" { resource "aws_instance" "k8s-etcd" {
ami = data.aws_ami.distro.id ami = "${data.aws_ami.distro.id}"
instance_type = var.aws_etcd_size instance_type = "${var.aws_etcd_size}"
count = var.aws_etcd_num count = "${var.aws_etcd_num}"
availability_zone = element(slice(data.aws_availability_zones.available.names, 0, 2), count.index) availability_zone = "${element(slice(data.aws_availability_zones.available.names, 0, 2), count.index)}"
subnet_id = element(module.aws-vpc.aws_subnet_ids_private, count.index) subnet_id = "${element(module.aws-vpc.aws_subnet_ids_private, count.index)}"
vpc_security_group_ids = module.aws-vpc.aws_security_group vpc_security_group_ids = "${module.aws-vpc.aws_security_group}"
key_name = var.AWS_SSH_KEY_NAME key_name = "${var.AWS_SSH_KEY_NAME}"
tags = merge(var.default_tags, map( tags = "${merge(var.default_tags, map(
"Name", "kubernetes-${var.aws_cluster_name}-etcd${count.index}", "Name", "kubernetes-${var.aws_cluster_name}-etcd${count.index}",
"kubernetes.io/cluster/${var.aws_cluster_name}", "member", "kubernetes.io/cluster/${var.aws_cluster_name}", "member",
"Role", "etcd" "Role", "etcd"
)) ))}"
} }
resource "aws_instance" "k8s-worker" { resource "aws_instance" "k8s-worker" {
ami = data.aws_ami.distro.id ami = "${data.aws_ami.distro.id}"
instance_type = var.aws_kube_worker_size instance_type = "${var.aws_kube_worker_size}"
count = var.aws_kube_worker_num count = "${var.aws_kube_worker_num}"
availability_zone = element(slice(data.aws_availability_zones.available.names, 0, 2), count.index) availability_zone = "${element(slice(data.aws_availability_zones.available.names, 0, 2), count.index)}"
subnet_id = element(module.aws-vpc.aws_subnet_ids_private, count.index) subnet_id = "${element(module.aws-vpc.aws_subnet_ids_private, count.index)}"
vpc_security_group_ids = module.aws-vpc.aws_security_group vpc_security_group_ids = "${module.aws-vpc.aws_security_group}"
iam_instance_profile = module.aws-iam.kube-worker-profile iam_instance_profile = "${module.aws-iam.kube-worker-profile}"
key_name = var.AWS_SSH_KEY_NAME key_name = "${var.AWS_SSH_KEY_NAME}"
tags = merge(var.default_tags, map( tags = "${merge(var.default_tags, map(
"Name", "kubernetes-${var.aws_cluster_name}-worker${count.index}", "Name", "kubernetes-${var.aws_cluster_name}-worker${count.index}",
"kubernetes.io/cluster/${var.aws_cluster_name}", "member", "kubernetes.io/cluster/${var.aws_cluster_name}", "member",
"Role", "worker" "Role", "worker"
)) ))}"
} }
/* /*
@@ -146,16 +146,16 @@ resource "aws_instance" "k8s-worker" {
* *
*/ */
data "template_file" "inventory" { data "template_file" "inventory" {
template = file("${path.module}/templates/inventory.tpl") template = "${file("${path.module}/templates/inventory.tpl")}"
vars = { vars = {
public_ip_address_bastion = join("\n", formatlist("bastion ansible_host=%s", aws_instance.bastion-server.*.public_ip)) public_ip_address_bastion = "${join("\n", formatlist("bastion ansible_host=%s", aws_instance.bastion-server.*.public_ip))}"
connection_strings_master = join("\n", formatlist("%s ansible_host=%s", aws_instance.k8s-master.*.private_dns, aws_instance.k8s-master.*.private_ip)) connection_strings_master = "${join("\n", formatlist("%s ansible_host=%s", aws_instance.k8s-master.*.tags.Name, aws_instance.k8s-master.*.private_ip))}"
connection_strings_node = join("\n", formatlist("%s ansible_host=%s", aws_instance.k8s-worker.*.private_dns, aws_instance.k8s-worker.*.private_ip)) connection_strings_node = "${join("\n", formatlist("%s ansible_host=%s", aws_instance.k8s-worker.*.tags.Name, aws_instance.k8s-worker.*.private_ip))}"
connection_strings_etcd = join("\n", formatlist("%s ansible_host=%s", aws_instance.k8s-etcd.*.private_dns, aws_instance.k8s-etcd.*.private_ip)) connection_strings_etcd = "${join("\n", formatlist("%s ansible_host=%s", aws_instance.k8s-etcd.*.tags.Name, aws_instance.k8s-etcd.*.private_ip))}"
list_master = join("\n", aws_instance.k8s-master.*.private_dns) list_master = "${join("\n", aws_instance.k8s-master.*.tags.Name)}"
list_node = join("\n", aws_instance.k8s-worker.*.private_dns) list_node = "${join("\n", aws_instance.k8s-worker.*.tags.Name)}"
list_etcd = join("\n", aws_instance.k8s-etcd.*.private_dns) list_etcd = "${join("\n", aws_instance.k8s-etcd.*.tags.Name)}"
elb_api_fqdn = "apiserver_loadbalancer_domain_name=\"${module.aws-elb.aws_elb_api_fqdn}\"" elb_api_fqdn = "apiserver_loadbalancer_domain_name=\"${module.aws-elb.aws_elb_api_fqdn}\""
} }
} }
@@ -166,6 +166,6 @@ resource "null_resource" "inventories" {
} }
triggers = { triggers = {
template = data.template_file.inventory.rendered template = "${data.template_file.inventory.rendered}"
} }
} }

View File

@@ -1,19 +1,19 @@
resource "aws_security_group" "aws-elb" { resource "aws_security_group" "aws-elb" {
name = "kubernetes-${var.aws_cluster_name}-securitygroup-elb" name = "kubernetes-${var.aws_cluster_name}-securitygroup-elb"
vpc_id = var.aws_vpc_id vpc_id = "${var.aws_vpc_id}"
tags = merge(var.default_tags, map( tags = "${merge(var.default_tags, map(
"Name", "kubernetes-${var.aws_cluster_name}-securitygroup-elb" "Name", "kubernetes-${var.aws_cluster_name}-securitygroup-elb"
)) ))}"
} }
resource "aws_security_group_rule" "aws-allow-api-access" { resource "aws_security_group_rule" "aws-allow-api-access" {
type = "ingress" type = "ingress"
from_port = var.aws_elb_api_port from_port = "${var.aws_elb_api_port}"
to_port = var.k8s_secure_api_port to_port = "${var.k8s_secure_api_port}"
protocol = "TCP" protocol = "TCP"
cidr_blocks = ["0.0.0.0/0"] cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.aws-elb.id security_group_id = "${aws_security_group.aws-elb.id}"
} }
resource "aws_security_group_rule" "aws-allow-api-egress" { resource "aws_security_group_rule" "aws-allow-api-egress" {
@@ -22,19 +22,19 @@ resource "aws_security_group_rule" "aws-allow-api-egress" {
to_port = 65535 to_port = 65535
protocol = "TCP" protocol = "TCP"
cidr_blocks = ["0.0.0.0/0"] cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.aws-elb.id security_group_id = "${aws_security_group.aws-elb.id}"
} }
# Create a new AWS ELB for K8S API # Create a new AWS ELB for K8S API
resource "aws_elb" "aws-elb-api" { resource "aws_elb" "aws-elb-api" {
name = "kubernetes-elb-${var.aws_cluster_name}" name = "kubernetes-elb-${var.aws_cluster_name}"
subnets = var.aws_subnet_ids_public subnets = var.aws_subnet_ids_public
security_groups = [aws_security_group.aws-elb.id] security_groups = ["${aws_security_group.aws-elb.id}"]
listener { listener {
instance_port = var.k8s_secure_api_port instance_port = "${var.k8s_secure_api_port}"
instance_protocol = "tcp" instance_protocol = "tcp"
lb_port = var.aws_elb_api_port lb_port = "${var.aws_elb_api_port}"
lb_protocol = "tcp" lb_protocol = "tcp"
} }
@@ -42,7 +42,7 @@ resource "aws_elb" "aws-elb-api" {
healthy_threshold = 2 healthy_threshold = 2
unhealthy_threshold = 2 unhealthy_threshold = 2
timeout = 3 timeout = 3
target = "HTTPS:${var.k8s_secure_api_port}/healthz" target = "TCP:${var.k8s_secure_api_port}"
interval = 30 interval = 30
} }
@@ -51,7 +51,7 @@ resource "aws_elb" "aws-elb-api" {
connection_draining = true connection_draining = true
connection_draining_timeout = 400 connection_draining_timeout = 400
tags = merge(var.default_tags, map( tags = "${merge(var.default_tags, map(
"Name", "kubernetes-${var.aws_cluster_name}-elb-api" "Name", "kubernetes-${var.aws_cluster_name}-elb-api"
)) ))}"
} }

View File

@@ -1,7 +1,7 @@
output "aws_elb_api_id" { output "aws_elb_api_id" {
value = aws_elb.aws-elb-api.id value = "${aws_elb.aws-elb-api.id}"
} }
output "aws_elb_api_fqdn" { output "aws_elb_api_fqdn" {
value = aws_elb.aws-elb-api.dns_name value = "${aws_elb.aws-elb-api.dns_name}"
} }

View File

@@ -16,15 +16,15 @@ variable "k8s_secure_api_port" {
variable "aws_avail_zones" { variable "aws_avail_zones" {
description = "Availability Zones Used" description = "Availability Zones Used"
type = list(string) type = "list"
} }
variable "aws_subnet_ids_public" { variable "aws_subnet_ids_public" {
description = "IDs of Public Subnets" description = "IDs of Public Subnets"
type = list(string) type = "list"
} }
variable "default_tags" { variable "default_tags" {
description = "Tags for all resources" description = "Tags for all resources"
type = map(string) type = "map"
} }

View File

@@ -42,7 +42,7 @@ EOF
resource "aws_iam_role_policy" "kube-master" { resource "aws_iam_role_policy" "kube-master" {
name = "kubernetes-${var.aws_cluster_name}-master" name = "kubernetes-${var.aws_cluster_name}-master"
role = aws_iam_role.kube-master.id role = "${aws_iam_role.kube-master.id}"
policy = <<EOF policy = <<EOF
{ {
@@ -77,7 +77,7 @@ EOF
resource "aws_iam_role_policy" "kube-worker" { resource "aws_iam_role_policy" "kube-worker" {
name = "kubernetes-${var.aws_cluster_name}-node" name = "kubernetes-${var.aws_cluster_name}-node"
role = aws_iam_role.kube-worker.id role = "${aws_iam_role.kube-worker.id}"
policy = <<EOF policy = <<EOF
{ {
@@ -132,10 +132,10 @@ EOF
resource "aws_iam_instance_profile" "kube-master" { resource "aws_iam_instance_profile" "kube-master" {
name = "kube_${var.aws_cluster_name}_master_profile" name = "kube_${var.aws_cluster_name}_master_profile"
role = aws_iam_role.kube-master.name role = "${aws_iam_role.kube-master.name}"
} }
resource "aws_iam_instance_profile" "kube-worker" { resource "aws_iam_instance_profile" "kube-worker" {
name = "kube_${var.aws_cluster_name}_node_profile" name = "kube_${var.aws_cluster_name}_node_profile"
role = aws_iam_role.kube-worker.name role = "${aws_iam_role.kube-worker.name}"
} }

View File

@@ -1,7 +1,7 @@
output "kube-master-profile" { output "kube-master-profile" {
value = aws_iam_instance_profile.kube-master.name value = "${aws_iam_instance_profile.kube-master.name }"
} }
output "kube-worker-profile" { output "kube-worker-profile" {
value = aws_iam_instance_profile.kube-worker.name value = "${aws_iam_instance_profile.kube-worker.name }"
} }

View File

@@ -1,55 +1,55 @@
resource "aws_vpc" "cluster-vpc" { resource "aws_vpc" "cluster-vpc" {
cidr_block = var.aws_vpc_cidr_block cidr_block = "${var.aws_vpc_cidr_block}"
#DNS Related Entries #DNS Related Entries
enable_dns_support = true enable_dns_support = true
enable_dns_hostnames = true enable_dns_hostnames = true
tags = merge(var.default_tags, map( tags = "${merge(var.default_tags, map(
"Name", "kubernetes-${var.aws_cluster_name}-vpc" "Name", "kubernetes-${var.aws_cluster_name}-vpc"
)) ))}"
} }
resource "aws_eip" "cluster-nat-eip" { resource "aws_eip" "cluster-nat-eip" {
count = length(var.aws_cidr_subnets_public) count = "${length(var.aws_cidr_subnets_public)}"
vpc = true vpc = true
} }
resource "aws_internet_gateway" "cluster-vpc-internetgw" { resource "aws_internet_gateway" "cluster-vpc-internetgw" {
vpc_id = aws_vpc.cluster-vpc.id vpc_id = "${aws_vpc.cluster-vpc.id}"
tags = merge(var.default_tags, map( tags = "${merge(var.default_tags, map(
"Name", "kubernetes-${var.aws_cluster_name}-internetgw" "Name", "kubernetes-${var.aws_cluster_name}-internetgw"
)) ))}"
} }
resource "aws_subnet" "cluster-vpc-subnets-public" { resource "aws_subnet" "cluster-vpc-subnets-public" {
vpc_id = aws_vpc.cluster-vpc.id vpc_id = "${aws_vpc.cluster-vpc.id}"
count = length(var.aws_avail_zones) count = "${length(var.aws_avail_zones)}"
availability_zone = element(var.aws_avail_zones, count.index) availability_zone = "${element(var.aws_avail_zones, count.index)}"
cidr_block = element(var.aws_cidr_subnets_public, count.index) cidr_block = "${element(var.aws_cidr_subnets_public, count.index)}"
tags = merge(var.default_tags, map( tags = "${merge(var.default_tags, map(
"Name", "kubernetes-${var.aws_cluster_name}-${element(var.aws_avail_zones, count.index)}-public", "Name", "kubernetes-${var.aws_cluster_name}-${element(var.aws_avail_zones, count.index)}-public",
"kubernetes.io/cluster/${var.aws_cluster_name}", "member" "kubernetes.io/cluster/${var.aws_cluster_name}", "member"
)) ))}"
} }
resource "aws_nat_gateway" "cluster-nat-gateway" { resource "aws_nat_gateway" "cluster-nat-gateway" {
count = length(var.aws_cidr_subnets_public) count = "${length(var.aws_cidr_subnets_public)}"
allocation_id = element(aws_eip.cluster-nat-eip.*.id, count.index) allocation_id = "${element(aws_eip.cluster-nat-eip.*.id, count.index)}"
subnet_id = element(aws_subnet.cluster-vpc-subnets-public.*.id, count.index) subnet_id = "${element(aws_subnet.cluster-vpc-subnets-public.*.id, count.index)}"
} }
resource "aws_subnet" "cluster-vpc-subnets-private" { resource "aws_subnet" "cluster-vpc-subnets-private" {
vpc_id = aws_vpc.cluster-vpc.id vpc_id = "${aws_vpc.cluster-vpc.id}"
count = length(var.aws_avail_zones) count = "${length(var.aws_avail_zones)}"
availability_zone = element(var.aws_avail_zones, count.index) availability_zone = "${element(var.aws_avail_zones, count.index)}"
cidr_block = element(var.aws_cidr_subnets_private, count.index) cidr_block = "${element(var.aws_cidr_subnets_private, count.index)}"
tags = merge(var.default_tags, map( tags = "${merge(var.default_tags, map(
"Name", "kubernetes-${var.aws_cluster_name}-${element(var.aws_avail_zones, count.index)}-private" "Name", "kubernetes-${var.aws_cluster_name}-${element(var.aws_avail_zones, count.index)}-private"
)) ))}"
} }
#Routing in VPC #Routing in VPC
@@ -57,53 +57,53 @@ resource "aws_subnet" "cluster-vpc-subnets-private" {
#TODO: Do we need two routing tables for each subnet for redundancy or is one enough? #TODO: Do we need two routing tables for each subnet for redundancy or is one enough?
resource "aws_route_table" "kubernetes-public" { resource "aws_route_table" "kubernetes-public" {
vpc_id = aws_vpc.cluster-vpc.id vpc_id = "${aws_vpc.cluster-vpc.id}"
route { route {
cidr_block = "0.0.0.0/0" cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.cluster-vpc-internetgw.id gateway_id = "${aws_internet_gateway.cluster-vpc-internetgw.id}"
} }
tags = merge(var.default_tags, map( tags = "${merge(var.default_tags, map(
"Name", "kubernetes-${var.aws_cluster_name}-routetable-public" "Name", "kubernetes-${var.aws_cluster_name}-routetable-public"
)) ))}"
} }
resource "aws_route_table" "kubernetes-private" { resource "aws_route_table" "kubernetes-private" {
count = length(var.aws_cidr_subnets_private) count = "${length(var.aws_cidr_subnets_private)}"
vpc_id = aws_vpc.cluster-vpc.id vpc_id = "${aws_vpc.cluster-vpc.id}"
route { route {
cidr_block = "0.0.0.0/0" cidr_block = "0.0.0.0/0"
nat_gateway_id = element(aws_nat_gateway.cluster-nat-gateway.*.id, count.index) nat_gateway_id = "${element(aws_nat_gateway.cluster-nat-gateway.*.id, count.index)}"
} }
tags = merge(var.default_tags, map( tags = "${merge(var.default_tags, map(
"Name", "kubernetes-${var.aws_cluster_name}-routetable-private-${count.index}" "Name", "kubernetes-${var.aws_cluster_name}-routetable-private-${count.index}"
)) ))}"
} }
resource "aws_route_table_association" "kubernetes-public" { resource "aws_route_table_association" "kubernetes-public" {
count = length(var.aws_cidr_subnets_public) count = "${length(var.aws_cidr_subnets_public)}"
subnet_id = element(aws_subnet.cluster-vpc-subnets-public.*.id, count.index) subnet_id = "${element(aws_subnet.cluster-vpc-subnets-public.*.id,count.index)}"
route_table_id = aws_route_table.kubernetes-public.id route_table_id = "${aws_route_table.kubernetes-public.id}"
} }
resource "aws_route_table_association" "kubernetes-private" { resource "aws_route_table_association" "kubernetes-private" {
count = length(var.aws_cidr_subnets_private) count = "${length(var.aws_cidr_subnets_private)}"
subnet_id = element(aws_subnet.cluster-vpc-subnets-private.*.id, count.index) subnet_id = "${element(aws_subnet.cluster-vpc-subnets-private.*.id,count.index)}"
route_table_id = element(aws_route_table.kubernetes-private.*.id, count.index) route_table_id = "${element(aws_route_table.kubernetes-private.*.id,count.index)}"
} }
#Kubernetes Security Groups #Kubernetes Security Groups
resource "aws_security_group" "kubernetes" { resource "aws_security_group" "kubernetes" {
name = "kubernetes-${var.aws_cluster_name}-securitygroup" name = "kubernetes-${var.aws_cluster_name}-securitygroup"
vpc_id = aws_vpc.cluster-vpc.id vpc_id = "${aws_vpc.cluster-vpc.id}"
tags = merge(var.default_tags, map( tags = "${merge(var.default_tags, map(
"Name", "kubernetes-${var.aws_cluster_name}-securitygroup" "Name", "kubernetes-${var.aws_cluster_name}-securitygroup"
)) ))}"
} }
resource "aws_security_group_rule" "allow-all-ingress" { resource "aws_security_group_rule" "allow-all-ingress" {
@@ -111,8 +111,8 @@ resource "aws_security_group_rule" "allow-all-ingress" {
from_port = 0 from_port = 0
to_port = 65535 to_port = 65535
protocol = "-1" protocol = "-1"
cidr_blocks = [var.aws_vpc_cidr_block] cidr_blocks = ["${var.aws_vpc_cidr_block}"]
security_group_id = aws_security_group.kubernetes.id security_group_id = "${aws_security_group.kubernetes.id}"
} }
resource "aws_security_group_rule" "allow-all-egress" { resource "aws_security_group_rule" "allow-all-egress" {
@@ -121,7 +121,7 @@ resource "aws_security_group_rule" "allow-all-egress" {
to_port = 65535 to_port = 65535
protocol = "-1" protocol = "-1"
cidr_blocks = ["0.0.0.0/0"] cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.kubernetes.id security_group_id = "${aws_security_group.kubernetes.id}"
} }
resource "aws_security_group_rule" "allow-ssh-connections" { resource "aws_security_group_rule" "allow-ssh-connections" {
@@ -130,5 +130,5 @@ resource "aws_security_group_rule" "allow-ssh-connections" {
to_port = 22 to_port = 22
protocol = "TCP" protocol = "TCP"
cidr_blocks = ["0.0.0.0/0"] cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.kubernetes.id security_group_id = "${aws_security_group.kubernetes.id}"
} }

View File

@@ -1,5 +1,5 @@
output "aws_vpc_id" { output "aws_vpc_id" {
value = aws_vpc.cluster-vpc.id value = "${aws_vpc.cluster-vpc.id}"
} }
output "aws_subnet_ids_private" { output "aws_subnet_ids_private" {
@@ -15,5 +15,5 @@ output "aws_security_group" {
} }
output "default_tags" { output "default_tags" {
value = var.default_tags value = "${var.default_tags}"
} }

View File

@@ -8,20 +8,20 @@ variable "aws_cluster_name" {
variable "aws_avail_zones" { variable "aws_avail_zones" {
description = "AWS Availability Zones Used" description = "AWS Availability Zones Used"
type = list(string) type = "list"
} }
variable "aws_cidr_subnets_private" { variable "aws_cidr_subnets_private" {
description = "CIDR Blocks for private subnets in Availability zones" description = "CIDR Blocks for private subnets in Availability zones"
type = list(string) type = "list"
} }
variable "aws_cidr_subnets_public" { variable "aws_cidr_subnets_public" {
description = "CIDR Blocks for public subnets in Availability zones" description = "CIDR Blocks for public subnets in Availability zones"
type = list(string) type = "list"
} }
variable "default_tags" { variable "default_tags" {
description = "Default tags for all resources" description = "Default tags for all resources"
type = map(string) type = "map"
} }

View File

@@ -1,17 +1,17 @@
output "bastion_ip" { output "bastion_ip" {
value = join("\n", aws_instance.bastion-server.*.public_ip) value = "${join("\n", aws_instance.bastion-server.*.public_ip)}"
} }
output "masters" { output "masters" {
value = join("\n", aws_instance.k8s-master.*.private_ip) value = "${join("\n", aws_instance.k8s-master.*.private_ip)}"
} }
output "workers" { output "workers" {
value = join("\n", aws_instance.k8s-worker.*.private_ip) value = "${join("\n", aws_instance.k8s-worker.*.private_ip)}"
} }
output "etcd" { output "etcd" {
value = join("\n", aws_instance.k8s-etcd.*.private_ip) value = "${join("\n", aws_instance.k8s-etcd.*.private_ip)}"
} }
output "aws_elb_api_fqdn" { output "aws_elb_api_fqdn" {
@@ -19,9 +19,9 @@ output "aws_elb_api_fqdn" {
} }
output "inventory" { output "inventory" {
value = data.template_file.inventory.rendered value = "${data.template_file.inventory.rendered}"
} }
output "default_tags" { output "default_tags" {
value = var.default_tags value = "${var.default_tags}"
} }

View File

@@ -25,7 +25,7 @@ data "aws_ami" "distro" {
filter { filter {
name = "name" name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*"] values = ["CoreOS-stable-*"]
} }
filter { filter {
@@ -33,7 +33,7 @@ data "aws_ami" "distro" {
values = ["hvm"] values = ["hvm"]
} }
owners = ["099720109477"] # Canonical owners = ["595879546273"] #CoreOS
} }
//AWS VPC Variables //AWS VPC Variables
@@ -44,12 +44,12 @@ variable "aws_vpc_cidr_block" {
variable "aws_cidr_subnets_private" { variable "aws_cidr_subnets_private" {
description = "CIDR Blocks for private subnets in Availability Zones" description = "CIDR Blocks for private subnets in Availability Zones"
type = list(string) type = "list"
} }
variable "aws_cidr_subnets_public" { variable "aws_cidr_subnets_public" {
description = "CIDR Blocks for public subnets in Availability Zones" description = "CIDR Blocks for public subnets in Availability Zones"
type = list(string) type = "list"
} }
//AWS EC2 Settings //AWS EC2 Settings
@@ -101,7 +101,7 @@ variable "k8s_secure_api_port" {
variable "default_tags" { variable "default_tags" {
description = "Default tags for all resources" description = "Default tags for all resources"
type = map(string) type = "map"
} }
variable "inventory_file" { variable "inventory_file" {

View File

@@ -1,90 +0,0 @@
# Kubernetes on GCP with Terraform
Provision a Kubernetes cluster on GCP using Terraform and Kubespray
## Overview
The setup looks like following
```text
Kubernetes cluster
+-----------------------+
+---------------+ | +--------------+ |
| | | | +--------------+ |
| API server LB +---------> | | | |
| | | | | Master/etcd | |
+---------------+ | | | node(s) | |
| +-+ | |
| +--------------+ |
| ^ |
| | |
| v |
+---------------+ | +--------------+ |
| | | | +--------------+ |
| Ingress LB +---------> | | | |
| | | | | Worker | |
+---------------+ | | | node(s) | |
| +-+ | |
| +--------------+ |
+-----------------------+
```
## Requirements
* Terraform 0.12.0 or newer
## Quickstart
To get a cluster up and running you'll need a JSON keyfile.
Set the path to the file in the `tfvars.json` file and run the following:
```bash
terraform apply -var-file tfvars.json -state dev-cluster.tfstate -var gcp_project_id=<ID of your GCP project> -var keyfile_location=<location of the json keyfile>
```
To generate kubespray inventory based on the terraform state file you can run the following:
```bash
./generate-inventory.sh dev-cluster.tfstate > inventory.ini
```
You should now have a inventory file named `inventory.ini` that you can use with kubespray, e.g.
```bash
ansible-playbook -i contrib/terraform/gcs/inventory.ini cluster.yml -b -v
```
## Variables
### Required
* `keyfile_location`: Location to the keyfile to use as credentials for the google terraform provider
* `gcp_project_id`: ID of the GCP project to deploy the cluster in
* `ssh_pub_key`: Path to public ssh key to use for all machines
* `region`: The region where to run the cluster
* `machines`: Machines to provision. Key of this object will be used as the name of the machine
* `node_type`: The role of this node *(master|worker)*
* `size`: The size to use
* `zone`: The zone the machine should run in
* `additional_disks`: Extra disks to add to the machine. Key of this object will be used as the disk name
* `size`: Size of the disk (in GB)
* `boot_disk`: The boot disk to use
* `image_name`: Name of the image
* `size`: Size of the boot disk (in GB)
* `ssh_whitelist`: List of IP ranges (CIDR) that will be allowed to ssh to the nodes
* `api_server_whitelist`: List of IP ranges (CIDR) that will be allowed to connect to the API server
* `nodeport_whitelist`: List of IP ranges (CIDR) that will be allowed to connect to the kubernetes nodes on port 30000-32767 (kubernetes nodeports)
### Optional
* `prefix`: Prefix to use for all resources, required to be unique for all clusters in the same project *(Defaults to `default`)*
* `master_sa_email`: Service account email to use for the master nodes *(Defaults to `""`, auto generate one)*
* `master_sa_scopes`: Service account email to use for the master nodes *(Defaults to `["https://www.googleapis.com/auth/cloud-platform"]`)*
* `worker_sa_email`: Service account email to use for the worker nodes *(Defaults to `""`, auto generate one)*
* `worker_sa_scopes`: Service account email to use for the worker nodes *(Defaults to `["https://www.googleapis.com/auth/cloud-platform"]`)*
An example variables file can be found `tfvars.json`
## Known limitations
This solution does not provide a solution to use a bastion host. Thus all the nodes must expose a public IP for kubespray to work.

View File

@@ -1,76 +0,0 @@
#!/bin/bash
#
# Generates a inventory file based on the terraform output.
# After provisioning a cluster, simply run this command and supply the terraform state file
# Default state file is terraform.tfstate
#
set -e
usage () {
echo "Usage: $0 <state file>" >&2
exit 1
}
if [[ $# -ne 1 ]]; then
usage
fi
TF_STATE_FILE=${1}
if [[ ! -f "${TF_STATE_FILE}" ]]; then
echo "ERROR: state file ${TF_STATE_FILE} doesn't exist" >&2
usage
fi
TF_OUT=$(terraform output -state "${TF_STATE_FILE}" -json)
MASTERS=$(jq -r '.master_ips.value | to_entries[]' <(echo "${TF_OUT}"))
WORKERS=$(jq -r '.worker_ips.value | to_entries[]' <(echo "${TF_OUT}"))
mapfile -t MASTER_NAMES < <(jq -r '.key' <(echo "${MASTERS}"))
mapfile -t WORKER_NAMES < <(jq -r '.key' <(echo "${WORKERS}"))
API_LB=$(jq -r '.control_plane_lb_ip_address.value' <(echo "${TF_OUT}"))
# Generate master hosts
i=1
for name in "${MASTER_NAMES[@]}"; do
private_ip=$(jq -r '. | select( .key=='"\"${name}\""' ) | .value.private_ip' <(echo "${MASTERS}"))
public_ip=$(jq -r '. | select( .key=='"\"${name}\""' ) | .value.public_ip' <(echo "${MASTERS}"))
echo "${name} ansible_user=ubuntu ansible_host=${public_ip} ip=${private_ip} etcd_member_name=etcd${i}"
i=$(( i + 1 ))
done
# Generate worker hosts
for name in "${WORKER_NAMES[@]}"; do
private_ip=$(jq -r '. | select( .key=='"\"${name}\""' ) | .value.private_ip' <(echo "${WORKERS}"))
public_ip=$(jq -r '. | select( .key=='"\"${name}\""' ) | .value.public_ip' <(echo "${WORKERS}"))
echo "${name} ansible_user=ubuntu ansible_host=${public_ip} ip=${private_ip}"
done
echo ""
echo "[kube-master]"
for name in "${MASTER_NAMES[@]}"; do
echo "${name}"
done
echo ""
echo "[kube-master:vars]"
echo "supplementary_addresses_in_ssl_keys = [ '${API_LB}' ]" # Add LB address to API server certificate
echo ""
echo "[etcd]"
for name in "${MASTER_NAMES[@]}"; do
echo "${name}"
done
echo ""
echo "[kube-node]"
for name in "${WORKER_NAMES[@]}"; do
echo "${name}"
done
echo ""
echo "[k8s-cluster:children]"
echo "kube-master"
echo "kube-node"

View File

@@ -1,24 +0,0 @@
provider "google" {
credentials = file(var.keyfile_location)
region = var.region
project = var.gcp_project_id
version = "~> 3.48"
}
module "kubernetes" {
source = "./modules/kubernetes-cluster"
region = var.region
prefix = var.prefix
machines = var.machines
ssh_pub_key = var.ssh_pub_key
master_sa_email = var.master_sa_email
master_sa_scopes = var.master_sa_scopes
worker_sa_email = var.worker_sa_email
worker_sa_scopes = var.worker_sa_scopes
ssh_whitelist = var.ssh_whitelist
api_server_whitelist = var.api_server_whitelist
nodeport_whitelist = var.nodeport_whitelist
}

View File

@@ -1,360 +0,0 @@
#################################################
##
## General
##
resource "google_compute_network" "main" {
name = "${var.prefix}-network"
}
resource "google_compute_subnetwork" "main" {
name = "${var.prefix}-subnet"
network = google_compute_network.main.name
ip_cidr_range = var.private_network_cidr
region = var.region
}
resource "google_compute_firewall" "deny_all" {
name = "${var.prefix}-default-firewall"
network = google_compute_network.main.name
priority = 1000
deny {
protocol = "all"
}
}
resource "google_compute_firewall" "allow_internal" {
name = "${var.prefix}-internal-firewall"
network = google_compute_network.main.name
priority = 500
source_ranges = [var.private_network_cidr]
allow {
protocol = "all"
}
}
resource "google_compute_firewall" "ssh" {
name = "${var.prefix}-ssh-firewall"
network = google_compute_network.main.name
priority = 100
source_ranges = var.ssh_whitelist
allow {
protocol = "tcp"
ports = ["22"]
}
}
resource "google_compute_firewall" "api_server" {
name = "${var.prefix}-api-server-firewall"
network = google_compute_network.main.name
priority = 100
source_ranges = var.api_server_whitelist
allow {
protocol = "tcp"
ports = ["6443"]
}
}
resource "google_compute_firewall" "nodeport" {
name = "${var.prefix}-nodeport-firewall"
network = google_compute_network.main.name
priority = 100
source_ranges = var.nodeport_whitelist
allow {
protocol = "tcp"
ports = ["30000-32767"]
}
}
resource "google_compute_firewall" "ingress_http" {
name = "${var.prefix}-http-ingress-firewall"
network = google_compute_network.main.name
priority = 100
allow {
protocol = "tcp"
ports = ["80"]
}
}
resource "google_compute_firewall" "ingress_https" {
name = "${var.prefix}-https-ingress-firewall"
network = google_compute_network.main.name
priority = 100
allow {
protocol = "tcp"
ports = ["443"]
}
}
#################################################
##
## Local variables
##
locals {
master_target_list = [
for name, machine in google_compute_instance.master :
"${machine.zone}/${machine.name}"
]
worker_target_list = [
for name, machine in google_compute_instance.worker :
"${machine.zone}/${machine.name}"
]
master_disks = flatten([
for machine_name, machine in var.machines : [
for disk_name, disk in machine.additional_disks : {
"${machine_name}-${disk_name}" = {
"machine_name": machine_name,
"machine": machine,
"disk_size": disk.size,
"disk_name": disk_name
}
}
]
if machine.node_type == "master"
])
worker_disks = flatten([
for machine_name, machine in var.machines : [
for disk_name, disk in machine.additional_disks : {
"${machine_name}-${disk_name}" = {
"machine_name": machine_name,
"machine": machine,
"disk_size": disk.size,
"disk_name": disk_name
}
}
]
if machine.node_type == "worker"
])
}
#################################################
##
## Master
##
resource "google_compute_address" "master" {
for_each = {
for name, machine in var.machines :
name => machine
if machine.node_type == "master"
}
name = "${var.prefix}-${each.key}-pip"
address_type = "EXTERNAL"
region = var.region
}
resource "google_compute_disk" "master" {
for_each = {
for item in local.master_disks :
keys(item)[0] => values(item)[0]
}
name = "${var.prefix}-${each.key}"
type = "pd-ssd"
zone = each.value.machine.zone
size = each.value.disk_size
physical_block_size_bytes = 4096
}
resource "google_compute_attached_disk" "master" {
for_each = {
for item in local.master_disks :
keys(item)[0] => values(item)[0]
}
disk = google_compute_disk.master[each.key].id
instance = google_compute_instance.master[each.value.machine_name].id
}
resource "google_compute_instance" "master" {
for_each = {
for name, machine in var.machines :
name => machine
if machine.node_type == "master"
}
name = "${var.prefix}-${each.key}"
machine_type = each.value.size
zone = each.value.zone
tags = ["master"]
boot_disk {
initialize_params {
image = each.value.boot_disk.image_name
size = each.value.boot_disk.size
}
}
network_interface {
subnetwork = google_compute_subnetwork.main.name
access_config {
nat_ip = google_compute_address.master[each.key].address
}
}
metadata = {
ssh-keys = "ubuntu:${trimspace(file(pathexpand(var.ssh_pub_key)))}"
}
service_account {
email = var.master_sa_email
scopes = var.master_sa_scopes
}
# Since we use google_compute_attached_disk we need to ignore this
lifecycle {
ignore_changes = ["attached_disk"]
}
}
resource "google_compute_forwarding_rule" "master_lb" {
name = "${var.prefix}-master-lb-forward-rule"
port_range = "6443"
target = google_compute_target_pool.master_lb.id
}
resource "google_compute_target_pool" "master_lb" {
name = "${var.prefix}-master-lb-pool"
instances = local.master_target_list
}
#################################################
##
## Worker
##
resource "google_compute_disk" "worker" {
for_each = {
for item in local.worker_disks :
keys(item)[0] => values(item)[0]
}
name = "${var.prefix}-${each.key}"
type = "pd-ssd"
zone = each.value.machine.zone
size = each.value.disk_size
physical_block_size_bytes = 4096
}
resource "google_compute_attached_disk" "worker" {
for_each = {
for item in local.worker_disks :
keys(item)[0] => values(item)[0]
}
disk = google_compute_disk.worker[each.key].id
instance = google_compute_instance.worker[each.value.machine_name].id
}
resource "google_compute_address" "worker" {
for_each = {
for name, machine in var.machines :
name => machine
if machine.node_type == "worker"
}
name = "${var.prefix}-${each.key}-pip"
address_type = "EXTERNAL"
region = var.region
}
resource "google_compute_instance" "worker" {
for_each = {
for name, machine in var.machines :
name => machine
if machine.node_type == "worker"
}
name = "${var.prefix}-${each.key}"
machine_type = each.value.size
zone = each.value.zone
tags = ["worker"]
boot_disk {
initialize_params {
image = each.value.boot_disk.image_name
size = each.value.boot_disk.size
}
}
network_interface {
subnetwork = google_compute_subnetwork.main.name
access_config {
nat_ip = google_compute_address.worker[each.key].address
}
}
metadata = {
ssh-keys = "ubuntu:${trimspace(file(pathexpand(var.ssh_pub_key)))}"
}
service_account {
email = var.worker_sa_email
scopes = var.worker_sa_scopes
}
# Since we use google_compute_attached_disk we need to ignore this
lifecycle {
ignore_changes = ["attached_disk"]
}
}
resource "google_compute_address" "worker_lb" {
name = "${var.prefix}-worker-lb-address"
address_type = "EXTERNAL"
region = var.region
}
resource "google_compute_forwarding_rule" "worker_http_lb" {
name = "${var.prefix}-worker-http-lb-forward-rule"
ip_address = google_compute_address.worker_lb.address
port_range = "80"
target = google_compute_target_pool.worker_lb.id
}
resource "google_compute_forwarding_rule" "worker_https_lb" {
name = "${var.prefix}-worker-https-lb-forward-rule"
ip_address = google_compute_address.worker_lb.address
port_range = "443"
target = google_compute_target_pool.worker_lb.id
}
resource "google_compute_target_pool" "worker_lb" {
name = "${var.prefix}-worker-lb-pool"
instances = local.worker_target_list
}

View File

@@ -1,27 +0,0 @@
output "master_ip_addresses" {
value = {
for key, instance in google_compute_instance.master :
instance.name => {
"private_ip" = instance.network_interface.0.network_ip
"public_ip" = instance.network_interface.0.access_config.0.nat_ip
}
}
}
output "worker_ip_addresses" {
value = {
for key, instance in google_compute_instance.worker :
instance.name => {
"private_ip" = instance.network_interface.0.network_ip
"public_ip" = instance.network_interface.0.access_config.0.nat_ip
}
}
}
output "ingress_controller_lb_ip_address" {
value = google_compute_address.worker_lb.address
}
output "control_plane_lb_ip_address" {
value = google_compute_forwarding_rule.master_lb.ip_address
}

View File

@@ -1,54 +0,0 @@
variable "region" {
type = string
}
variable "prefix" {}
variable "machines" {
type = map(object({
node_type = string
size = string
zone = string
additional_disks = map(object({
size = number
}))
boot_disk = object({
image_name = string
size = number
})
}))
}
variable "master_sa_email" {
type = string
}
variable "master_sa_scopes" {
type = list(string)
}
variable "worker_sa_email" {
type = string
}
variable "worker_sa_scopes" {
type = list(string)
}
variable "ssh_pub_key" {}
variable "ssh_whitelist" {
type = list(string)
}
variable "api_server_whitelist" {
type = list(string)
}
variable "nodeport_whitelist" {
type = list(string)
}
variable "private_network_cidr" {
default = "10.0.10.0/24"
}

View File

@@ -1,15 +0,0 @@
output "master_ips" {
value = module.kubernetes.master_ip_addresses
}
output "worker_ips" {
value = module.kubernetes.worker_ip_addresses
}
output "ingress_controller_lb_ip_address" {
value = module.kubernetes.ingress_controller_lb_ip_address
}
output "control_plane_lb_ip_address" {
value = module.kubernetes.control_plane_lb_ip_address
}

View File

@@ -1,60 +0,0 @@
{
"gcp_project_id": "GCP_PROJECT_ID",
"region": "us-central1",
"ssh_pub_key": "~/.ssh/id_rsa.pub",
"keyfile_location": "service-account.json",
"prefix": "development",
"ssh_whitelist": [
"1.2.3.4/32"
],
"api_server_whitelist": [
"1.2.3.4/32"
],
"nodeport_whitelist": [
"1.2.3.4/32"
],
"machines": {
"master-0": {
"node_type": "master",
"size": "n1-standard-2",
"zone": "us-central1-a",
"additional_disks": {},
"boot_disk": {
"image_name": "ubuntu-os-cloud/ubuntu-1804-bionic-v20201116",
"size": 50
}
},
"worker-0": {
"node_type": "worker",
"size": "n1-standard-8",
"zone": "us-central1-a",
"additional_disks": {
"extra-disk-1": {
"size": 100
}
},
"boot_disk": {
"image_name": "ubuntu-os-cloud/ubuntu-1804-bionic-v20201116",
"size": 50
}
},
"worker-1": {
"node_type": "worker",
"size": "n1-standard-8",
"zone": "us-central1-a",
"additional_disks": {
"extra-disk-1": {
"size": 100
}
},
"boot_disk": {
"image_name": "ubuntu-os-cloud/ubuntu-1804-bionic-v20201116",
"size": 50
}
}
}
}

View File

@@ -1,72 +0,0 @@
variable keyfile_location {
description = "Location of the json keyfile to use with the google provider"
type = string
}
variable region {
description = "Region of all resources"
type = string
}
variable gcp_project_id {
description = "ID of the project"
type = string
}
variable prefix {
description = "Prefix for resource names"
default = "default"
}
variable machines {
description = "Cluster machines"
type = map(object({
node_type = string
size = string
zone = string
additional_disks = map(object({
size = number
}))
boot_disk = object({
image_name = string
size = number
})
}))
}
variable "master_sa_email" {
type = string
default = ""
}
variable "master_sa_scopes" {
type = list(string)
default = ["https://www.googleapis.com/auth/cloud-platform"]
}
variable "worker_sa_email" {
type = string
default = ""
}
variable "worker_sa_scopes" {
type = list(string)
default = ["https://www.googleapis.com/auth/cloud-platform"]
}
variable ssh_pub_key {
description = "Path to public SSH key file which is injected into the VMs."
type = string
}
variable ssh_whitelist {
type = list(string)
}
variable api_server_whitelist {
type = list(string)
}
variable nodeport_whitelist {
type = list(string)
}

View File

@@ -1,15 +1,14 @@
# Kubernetes on OpenStack with Terraform # Kubernetes on Openstack with Terraform
Provision a Kubernetes cluster with [Terraform](https://www.terraform.io) on Provision a Kubernetes cluster with [Terraform](https://www.terraform.io) on
OpenStack. Openstack.
## Status ## Status
This will install a Kubernetes cluster on an OpenStack Cloud. It should work on This will install a Kubernetes cluster on an Openstack Cloud. It should work on
most modern installs of OpenStack that support the basic services. most modern installs of OpenStack that support the basic services.
### Known compatible public clouds ### Known compatible public clouds
- [Auro](https://auro.io/) - [Auro](https://auro.io/)
- [Betacloud](https://www.betacloud.io/) - [Betacloud](https://www.betacloud.io/)
- [CityCloud](https://www.citycloud.com/) - [CityCloud](https://www.citycloud.com/)
@@ -24,8 +23,8 @@ most modern installs of OpenStack that support the basic services.
- [VexxHost](https://vexxhost.com/) - [VexxHost](https://vexxhost.com/)
- [Zetta](https://www.zetta.io/) - [Zetta](https://www.zetta.io/)
## Approach
## Approach
The terraform configuration inspects variables found in The terraform configuration inspects variables found in
[variables.tf](variables.tf) to create resources in your OpenStack cluster. [variables.tf](variables.tf) to create resources in your OpenStack cluster.
There is a [python script](../terraform.py) that reads the generated`.tfstate` There is a [python script](../terraform.py) that reads the generated`.tfstate`
@@ -33,31 +32,16 @@ file to generate a dynamic inventory that is consumed by the main ansible script
to actually install kubernetes and stand up the cluster. to actually install kubernetes and stand up the cluster.
### Networking ### Networking
The configuration includes creating a private subnet with a router to the The configuration includes creating a private subnet with a router to the
external net. It will allocate floating IPs from a pool and assign them to the external net. It will allocate floating IPs from a pool and assign them to the
hosts where that makes sense. You have the option of creating bastion hosts hosts where that makes sense. You have the option of creating bastion hosts
inside the private subnet to access the nodes there. Alternatively, a node with inside the private subnet to access the nodes there. Alternatively, a node with
a floating IP can be used as a jump host to nodes without. a floating IP can be used as a jump host to nodes without.
#### Using an existing router
It is possible to use an existing router instead of creating one. To use an
existing router set the router\_id variable to the uuid of the router you wish
to use.
For example:
```ShellSession
router_id = "00c542e7-6f46-4535-ae95-984c7f0391a3"
```
### Kubernetes Nodes ### Kubernetes Nodes
You can create many different kubernetes topologies by setting the number of You can create many different kubernetes topologies by setting the number of
different classes of hosts. For each class there are options for allocating different classes of hosts. For each class there are options for allocating
floating IP addresses or not. floating IP addresses or not.
- Master nodes with etcd - Master nodes with etcd
- Master nodes without etcd - Master nodes without etcd
- Standalone etcd hosts - Standalone etcd hosts
@@ -70,19 +54,17 @@ master nodes with etcd replicas. As an example, if you have three master nodes w
etcd replicas and three standalone etcd nodes, the script will fail since there are etcd replicas and three standalone etcd nodes, the script will fail since there are
now six total etcd replicas. now six total etcd replicas.
### GlusterFS shared file system ### GlusterFS
The Terraform configuration supports provisioning of an optional GlusterFS The Terraform configuration supports provisioning of an optional GlusterFS
shared file system based on a separate set of VMs. To enable this, you need to shared file system based on a separate set of VMs. To enable this, you need to
specify: specify:
- the number of Gluster hosts (minimum 2) - the number of Gluster hosts (minimum 2)
- Size of the non-ephemeral volumes to be attached to store the GlusterFS bricks - Size of the non-ephemeral volumes to be attached to store the GlusterFS bricks
- Other properties related to provisioning the hosts - Other properties related to provisioning the hosts
Even if you are using Flatcar Container Linux by Kinvolk for your cluster, you will still Even if you are using Container Linux by CoreOS for your cluster, you will still
need the GlusterFS VMs to be based on either Debian or RedHat based images. need the GlusterFS VMs to be based on either Debian or RedHat based images.
Flatcar Container Linux by Kinvolk cannot serve GlusterFS, but can connect to it through Container Linux by CoreOS cannot serve GlusterFS, but can connect to it through
binaries available on hyperkube v1.4.3_coreos.0 or higher. binaries available on hyperkube v1.4.3_coreos.0 or higher.
## Requirements ## Requirements
@@ -95,9 +77,7 @@ binaries available on hyperkube v1.4.3_coreos.0 or higher.
- you have a pair of keys generated that can be used to secure the new hosts - you have a pair of keys generated that can be used to secure the new hosts
## Module Architecture ## Module Architecture
The configuration is divided into three modules: The configuration is divided into three modules:
- Network - Network
- IPs - IPs
- Compute - Compute
@@ -110,13 +90,12 @@ to be updated.
You can force your existing IPs by modifying the compute variables in You can force your existing IPs by modifying the compute variables in
`kubespray.tf` as follows: `kubespray.tf` as follows:
```ini ```
k8s_master_fips = ["151.101.129.67"] k8s_master_fips = ["151.101.129.67"]
k8s_node_fips = ["151.101.129.68"] k8s_node_fips = ["151.101.129.68"]
``` ```
## Terraform ## Terraform
Terraform will be used to provision all of the OpenStack resources with base software as appropriate. Terraform will be used to provision all of the OpenStack resources with base software as appropriate.
### Configuration ### Configuration
@@ -126,10 +105,10 @@ Terraform will be used to provision all of the OpenStack resources with base sof
Create an inventory directory for your cluster by copying the existing sample and linking the `hosts` script (used to build the inventory based on Terraform state): Create an inventory directory for your cluster by copying the existing sample and linking the `hosts` script (used to build the inventory based on Terraform state):
```ShellSession ```ShellSession
cp -LRp contrib/terraform/openstack/sample-inventory inventory/$CLUSTER $ cp -LRp contrib/terraform/openstack/sample-inventory inventory/$CLUSTER
cd inventory/$CLUSTER $ cd inventory/$CLUSTER
ln -s ../../contrib/terraform/openstack/hosts $ ln -s ../../contrib/terraform/openstack/hosts
ln -s ../../contrib $ ln -s ../../contrib
``` ```
This will be the base for subsequent Terraform commands. This will be the base for subsequent Terraform commands.
@@ -149,13 +128,13 @@ please read the [OpenStack provider documentation](https://www.terraform.io/docs
The recommended authentication method is to describe credentials in a YAML file `clouds.yaml` that can be stored in: The recommended authentication method is to describe credentials in a YAML file `clouds.yaml` that can be stored in:
- the current directory * the current directory
- `~/.config/openstack` * `~/.config/openstack`
- `/etc/openstack` * `/etc/openstack`
`clouds.yaml`: `clouds.yaml`:
```yaml ```
clouds: clouds:
mycloud: mycloud:
auth: auth:
@@ -173,7 +152,7 @@ clouds:
If you have multiple clouds defined in your `clouds.yaml` file you can choose If you have multiple clouds defined in your `clouds.yaml` file you can choose
the one you want to use with the environment variable `OS_CLOUD`: the one you want to use with the environment variable `OS_CLOUD`:
```ShellSession ```
export OS_CLOUD=mycloud export OS_CLOUD=mycloud
``` ```
@@ -185,7 +164,7 @@ from Horizon under *Project* -> *Compute* -> *Access & Security* -> *API Access*
With identity v2: With identity v2:
```ShellSession ```
source openrc source openrc
env | grep OS env | grep OS
@@ -202,7 +181,7 @@ OS_IDENTITY_API_VERSION=2
With identity v3: With identity v3:
```ShellSession ```
source openrc source openrc
env | grep OS env | grep OS
@@ -219,24 +198,24 @@ OS_IDENTITY_API_VERSION=3
OS_USER_DOMAIN_NAME=Default OS_USER_DOMAIN_NAME=Default
``` ```
Terraform does not support a mix of DomainName and DomainID, choose one or the other: Terraform does not support a mix of DomainName and DomainID, choose one or the
other:
- provider.openstack: You must provide exactly one of DomainID or DomainName to authenticate by Username ```
* provider.openstack: You must provide exactly one of DomainID or DomainName to authenticate by Username
```
```ShellSession ```
unset OS_USER_DOMAIN_NAME unset OS_USER_DOMAIN_NAME
export OS_USER_DOMAIN_ID=default export OS_USER_DOMAIN_ID=default
```
or or
```ShellSession
unset OS_PROJECT_DOMAIN_ID unset OS_PROJECT_DOMAIN_ID
set OS_PROJECT_DOMAIN_NAME=Default set OS_PROJECT_DOMAIN_NAME=Default
``` ```
#### Cluster variables #### Cluster variables
The construction of the cluster is driven by values found in The construction of the cluster is driven by values found in
[variables.tf](variables.tf). [variables.tf](variables.tf).
@@ -250,7 +229,6 @@ For your cluster, edit `inventory/$CLUSTER/cluster.tfvars`.
|`network_dns_domain` | (Optional) The dns_domain for the internal network that will be generated | |`network_dns_domain` | (Optional) The dns_domain for the internal network that will be generated |
|`dns_nameservers`| An array of DNS name server names to be used by hosts in the internal subnet. | |`dns_nameservers`| An array of DNS name server names to be used by hosts in the internal subnet. |
|`floatingip_pool` | Name of the pool from which floating IPs will be allocated | |`floatingip_pool` | Name of the pool from which floating IPs will be allocated |
|`k8s_master_fips` | A list of floating IPs that you have already pre-allocated; they will be attached to master nodes instead of creating new random floating IPs. |
|`external_net` | UUID of the external network that will be routed to | |`external_net` | UUID of the external network that will be routed to |
|`flavor_k8s_master`,`flavor_k8s_node`,`flavor_etcd`, `flavor_bastion`,`flavor_gfs_node` | Flavor depends on your openstack installation, you can get available flavor IDs through `openstack flavor list` | |`flavor_k8s_master`,`flavor_k8s_node`,`flavor_etcd`, `flavor_bastion`,`flavor_gfs_node` | Flavor depends on your openstack installation, you can get available flavor IDs through `openstack flavor list` |
|`image`,`image_gfs` | Name of the image to use in provisioning the compute resources. Should already be loaded into glance. | |`image`,`image_gfs` | Name of the image to use in provisioning the compute resources. Should already be loaded into glance. |
@@ -276,114 +254,6 @@ For your cluster, edit `inventory/$CLUSTER/cluster.tfvars`.
|`etcd_root_volume_size_in_gb` | Size of the root volume for etcd nodes, 0 to use ephemeral storage | |`etcd_root_volume_size_in_gb` | Size of the root volume for etcd nodes, 0 to use ephemeral storage |
|`bastion_root_volume_size_in_gb` | Size of the root volume for bastions, 0 to use ephemeral storage | |`bastion_root_volume_size_in_gb` | Size of the root volume for bastions, 0 to use ephemeral storage |
|`use_server_group` | Create and use openstack nova servergroups, default: false | |`use_server_group` | Create and use openstack nova servergroups, default: false |
|`use_access_ip` | If 1, nodes with floating IPs will transmit internal cluster traffic via floating IPs; if 0 private IPs will be used instead. Default value is 1. |
|`k8s_nodes` | Map containing worker node definition, see explanation below |
##### k8s_nodes
Allows a custom defintion of worker nodes giving the operator full control over individual node flavor and
availability zone placement. To enable the use of this mode set the `number_of_k8s_nodes` and
`number_of_k8s_nodes_no_floating_ip` variables to 0. Then define your desired worker node configuration
using the `k8s_nodes` variable.
For example:
```ini
k8s_nodes = {
"1" = {
"az" = "sto1"
"flavor" = "83d8b44a-26a0-4f02-a981-079446926445"
"floating_ip" = true
},
"2" = {
"az" = "sto2"
"flavor" = "83d8b44a-26a0-4f02-a981-079446926445"
"floating_ip" = true
},
"3" = {
"az" = "sto3"
"flavor" = "83d8b44a-26a0-4f02-a981-079446926445"
"floating_ip" = true
}
}
```
Would result in the same configuration as:
```ini
number_of_k8s_nodes = 3
flavor_k8s_node = "83d8b44a-26a0-4f02-a981-079446926445"
az_list = ["sto1", "sto2", "sto3"]
```
And:
```ini
k8s_nodes = {
"ing-1" = {
"az" = "sto1"
"flavor" = "83d8b44a-26a0-4f02-a981-079446926445"
"floating_ip" = true
},
"ing-2" = {
"az" = "sto2"
"flavor" = "83d8b44a-26a0-4f02-a981-079446926445"
"floating_ip" = true
},
"ing-3" = {
"az" = "sto3"
"flavor" = "83d8b44a-26a0-4f02-a981-079446926445"
"floating_ip" = true
},
"big-1" = {
"az" = "sto1"
"flavor" = "3f73fc93-ec61-4808-88df-2580d94c1a9b"
"floating_ip" = false
},
"big-2" = {
"az" = "sto2"
"flavor" = "3f73fc93-ec61-4808-88df-2580d94c1a9b"
"floating_ip" = false
},
"big-3" = {
"az" = "sto3"
"flavor" = "3f73fc93-ec61-4808-88df-2580d94c1a9b"
"floating_ip" = false
},
"small-1" = {
"az" = "sto1"
"flavor" = "7a6a998f-ac7f-4fb8-a534-2175b254f75e"
"floating_ip" = false
},
"small-2" = {
"az" = "sto2"
"flavor" = "7a6a998f-ac7f-4fb8-a534-2175b254f75e"
"floating_ip" = false
},
"small-3" = {
"az" = "sto3"
"flavor" = "7a6a998f-ac7f-4fb8-a534-2175b254f75e"
"floating_ip" = false
}
}
```
Would result in three nodes in each availability zone each with their own separate naming,
flavor and floating ip configuration.
The "schema":
```ini
k8s_nodes = {
"key | node name suffix, must be unique" = {
"az" = string
"flavor" = string
"floating_ip" = bool
},
}
```
All values are required.
#### Terraform state files #### Terraform state files
@@ -391,10 +261,10 @@ In the cluster's inventory folder, the following files might be created (either
or manually), to prevent you from pushing them accidentally they are in a or manually), to prevent you from pushing them accidentally they are in a
`.gitignore` file in the `terraform/openstack` directory : `.gitignore` file in the `terraform/openstack` directory :
- `.terraform` * `.terraform`
- `.tfvars` * `.tfvars`
- `.tfstate` * `.tfstate`
- `.tfstate.backup` * `.tfstate.backup`
You can still add them manually if you want to. You can still add them manually if you want to.
@@ -404,19 +274,17 @@ Before Terraform can operate on your cluster you need to install the required
plugins. This is accomplished as follows: plugins. This is accomplished as follows:
```ShellSession ```ShellSession
cd inventory/$CLUSTER $ cd inventory/$CLUSTER
terraform init ../../contrib/terraform/openstack $ terraform init ../../contrib/terraform/openstack
``` ```
This should finish fairly quickly telling you Terraform has successfully initialized and loaded necessary modules. This should finish fairly quickly telling you Terraform has successfully initialized and loaded necessary modules.
### Provisioning cluster ### Provisioning cluster
You can apply the Terraform configuration to your cluster with the following command You can apply the Terraform configuration to your cluster with the following command
issued from your cluster's inventory directory (`inventory/$CLUSTER`): issued from your cluster's inventory directory (`inventory/$CLUSTER`):
```ShellSession ```ShellSession
terraform apply -var-file=cluster.tfvars ../../contrib/terraform/openstack $ terraform apply -var-file=cluster.tfvars ../../contrib/terraform/openstack
``` ```
if you chose to create a bastion host, this script will create if you chose to create a bastion host, this script will create
@@ -427,20 +295,18 @@ or move that file. If you want to use this, just leave it there, as ansible will
pick it up automatically. pick it up automatically.
### Destroying cluster ### Destroying cluster
You can destroy your new cluster with the following command issued from the cluster's inventory directory: You can destroy your new cluster with the following command issued from the cluster's inventory directory:
```ShellSession ```ShellSession
terraform destroy -var-file=cluster.tfvars ../../contrib/terraform/openstack $ terraform destroy -var-file=cluster.tfvars ../../contrib/terraform/openstack
``` ```
If you've started the Ansible run, it may also be a good idea to do some manual cleanup: If you've started the Ansible run, it may also be a good idea to do some manual cleanup:
- remove SSH keys from the destroyed cluster from your `~/.ssh/known_hosts` file * remove SSH keys from the destroyed cluster from your `~/.ssh/known_hosts` file
- clean up any temporary cache files: `rm /tmp/$CLUSTER-*` * clean up any temporary cache files: `rm /tmp/$CLUSTER-*`
### Debugging ### Debugging
You can enable debugging output from Terraform by setting You can enable debugging output from Terraform by setting
`OS_DEBUG` to 1 and`TF_LOG` to`DEBUG` before running the Terraform command. `OS_DEBUG` to 1 and`TF_LOG` to`DEBUG` before running the Terraform command.
@@ -448,8 +314,8 @@ You can enable debugging output from Terraform by setting
Terraform can output values that are useful for configure Neutron/Octavia LBaaS or Cinder persistent volume provisioning as part of your Kubernetes deployment: Terraform can output values that are useful for configure Neutron/Octavia LBaaS or Cinder persistent volume provisioning as part of your Kubernetes deployment:
- `private_subnet_id`: the subnet where your instances are running is used for `openstack_lbaas_subnet_id` - `private_subnet_id`: the subnet where your instances are running is used for `openstack_lbaas_subnet_id`
- `floating_network_id`: the network_id where the floating IP are provisioned is used for `openstack_lbaas_floating_network_id` - `floating_network_id`: the network_id where the floating IP are provisioned is used for `openstack_lbaas_floating_network_id`
## Ansible ## Ansible
@@ -460,9 +326,9 @@ Terraform can output values that are useful for configure Neutron/Octavia LBaaS
Ensure your local ssh-agent is running and your ssh key has been added. This Ensure your local ssh-agent is running and your ssh key has been added. This
step is required by the terraform provisioner: step is required by the terraform provisioner:
```ShellSession ```
eval $(ssh-agent -s) $ eval $(ssh-agent -s)
ssh-add ~/.ssh/id_rsa $ ssh-add ~/.ssh/id_rsa
``` ```
If you have deployed and destroyed a previous iteration of your cluster, you will need to clear out any stale keys from your SSH "known hosts" file ( `~/.ssh/known_hosts`). If you have deployed and destroyed a previous iteration of your cluster, you will need to clear out any stale keys from your SSH "known hosts" file ( `~/.ssh/known_hosts`).
@@ -474,13 +340,13 @@ generated`.tfstate` file to generate a dynamic inventory recognizes
some variables within a "metadata" block, defined in a "resource" some variables within a "metadata" block, defined in a "resource"
block (example): block (example):
```ini ```
resource "openstack_compute_instance_v2" "example" { resource "openstack_compute_instance_v2" "example" {
... ...
metadata { metadata {
ssh_user = "ubuntu" ssh_user = "ubuntu"
prefer_ipv6 = true prefer_ipv6 = true
python_bin = "/usr/bin/python3" python_bin = "/usr/bin/python3"
} }
... ...
} }
@@ -495,8 +361,8 @@ instance should be preferred over IPv4.
Bastion access will be determined by: Bastion access will be determined by:
- Your choice on the amount of bastion hosts (set by `number_of_bastions` terraform variable). - Your choice on the amount of bastion hosts (set by `number_of_bastions` terraform variable).
- The existence of nodes/masters with floating IPs (set by `number_of_k8s_masters`, `number_of_k8s_nodes`, `number_of_k8s_masters_no_etcd` terraform variables). - The existence of nodes/masters with floating IPs (set by `number_of_k8s_masters`, `number_of_k8s_nodes`, `number_of_k8s_masters_no_etcd` terraform variables).
If you have a bastion host, your ssh traffic will be directly routed through it. This is regardless of whether you have masters/nodes with a floating IP assigned. If you have a bastion host, your ssh traffic will be directly routed through it. This is regardless of whether you have masters/nodes with a floating IP assigned.
If you don't have a bastion host, but at least one of your masters/nodes have a floating IP, then ssh traffic will be tunneled by one of these machines. If you don't have a bastion host, but at least one of your masters/nodes have a floating IP, then ssh traffic will be tunneled by one of these machines.
@@ -505,9 +371,9 @@ So, either a bastion host, or at least master/node with a floating IP are requir
#### Test access #### Test access
Make sure you can connect to the hosts. Note that Flatcar Container Linux by Kinvolk will have a state `FAILED` due to Python not being present. This is okay, because Python will be installed during bootstrapping, so long as the hosts are not `UNREACHABLE`. Make sure you can connect to the hosts. Note that Container Linux by CoreOS will have a state `FAILED` due to Python not being present. This is okay, because Python will be installed during bootstrapping, so long as the hosts are not `UNREACHABLE`.
```ShellSession ```
$ ansible -i inventory/$CLUSTER/hosts -m ping all $ ansible -i inventory/$CLUSTER/hosts -m ping all
example-k8s_node-1 | SUCCESS => { example-k8s_node-1 | SUCCESS => {
"changed": false, "changed": false,
@@ -528,55 +394,48 @@ If it fails try to connect manually via SSH. It could be something as simple as
### Configure cluster variables ### Configure cluster variables
Edit `inventory/$CLUSTER/group_vars/all/all.yml`: Edit `inventory/$CLUSTER/group_vars/all/all.yml`:
- **bin_dir**: - **bin_dir**:
```
```yml
# Directory where the binaries will be installed # Directory where the binaries will be installed
# Default: # Default:
# bin_dir: /usr/local/bin # bin_dir: /usr/local/bin
# For Flatcar Container Linux by Kinvolk: # For Container Linux by CoreOS:
bin_dir: /opt/bin bin_dir: /opt/bin
``` ```
- and **cloud_provider**: - and **cloud_provider**:
```
```yml
cloud_provider: openstack cloud_provider: openstack
``` ```
Edit `inventory/$CLUSTER/group_vars/k8s-cluster/k8s-cluster.yml`: Edit `inventory/$CLUSTER/group_vars/k8s-cluster/k8s-cluster.yml`:
- Set variable **kube_network_plugin** to your desired networking plugin. - Set variable **kube_network_plugin** to your desired networking plugin.
- **flannel** works out-of-the-box - **flannel** works out-of-the-box
- **calico** requires [configuring OpenStack Neutron ports](/docs/openstack.md) to allow service and pod subnets - **calico** requires [configuring OpenStack Neutron ports](/docs/openstack.md) to allow service and pod subnets
```
```yml
# Choose network plugin (calico, weave or flannel) # Choose network plugin (calico, weave or flannel)
# Can also be set to 'cloud', which lets the cloud provider setup appropriate routing # Can also be set to 'cloud', which lets the cloud provider setup appropriate routing
kube_network_plugin: flannel kube_network_plugin: flannel
``` ```
- Set variable **resolvconf_mode** - Set variable **resolvconf_mode**
```
```yml
# Can be docker_dns, host_resolvconf or none # Can be docker_dns, host_resolvconf or none
# Default: # Default:
# resolvconf_mode: docker_dns # resolvconf_mode: docker_dns
# For Flatcar Container Linux by Kinvolk: # For Container Linux by CoreOS:
resolvconf_mode: host_resolvconf resolvconf_mode: host_resolvconf
``` ```
- Set max amount of attached cinder volume per host (default 256) - Set max amount of attached cinder volume per host (default 256)
```
```yml
node_volume_attach_limit: 26 node_volume_attach_limit: 26
``` ```
- Disable access_ip, this will make all innternal cluster traffic to be sent over local network when a floating IP is attached (default this value is set to 1)
```
use_access_ip: 0
```
### Deploy Kubernetes ### Deploy Kubernetes
```ShellSession ```
ansible-playbook --become -i inventory/$CLUSTER/hosts cluster.yml $ ansible-playbook --become -i inventory/$CLUSTER/hosts cluster.yml
``` ```
This will take some time as there are many tasks to run. This will take some time as there are many tasks to run.
@@ -584,36 +443,26 @@ This will take some time as there are many tasks to run.
## Kubernetes ## Kubernetes
### Set up kubectl ### Set up kubectl
1. [Install kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) on your workstation 1. [Install kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/) on your workstation
2. Add a route to the internal IP of a master node (if needed): 2. Add a route to the internal IP of a master node (if needed):
```
```ShellSession
sudo route add [master-internal-ip] gw [router-ip] sudo route add [master-internal-ip] gw [router-ip]
``` ```
or or
```
```ShellSession
sudo route add -net [internal-subnet]/24 gw [router-ip] sudo route add -net [internal-subnet]/24 gw [router-ip]
``` ```
3. List Kubernetes certificates & keys:
1. List Kubernetes certificates & keys: ```
```ShellSession
ssh [os-user]@[master-ip] sudo ls /etc/kubernetes/ssl/ ssh [os-user]@[master-ip] sudo ls /etc/kubernetes/ssl/
``` ```
4. Get `admin`'s certificates and keys:
1. Get `admin`'s certificates and keys: ```
```ShellSession
ssh [os-user]@[master-ip] sudo cat /etc/kubernetes/ssl/admin-kube-master-1-key.pem > admin-key.pem ssh [os-user]@[master-ip] sudo cat /etc/kubernetes/ssl/admin-kube-master-1-key.pem > admin-key.pem
ssh [os-user]@[master-ip] sudo cat /etc/kubernetes/ssl/admin-kube-master-1.pem > admin.pem ssh [os-user]@[master-ip] sudo cat /etc/kubernetes/ssl/admin-kube-master-1.pem > admin.pem
ssh [os-user]@[master-ip] sudo cat /etc/kubernetes/ssl/ca.pem > ca.pem ssh [os-user]@[master-ip] sudo cat /etc/kubernetes/ssl/ca.pem > ca.pem
``` ```
5. Configure kubectl:
1. Configure kubectl:
```ShellSession ```ShellSession
$ kubectl config set-cluster default-cluster --server=https://[master-internal-ip]:6443 \ $ kubectl config set-cluster default-cluster --server=https://[master-internal-ip]:6443 \
--certificate-authority=ca.pem --certificate-authority=ca.pem
@@ -626,104 +475,22 @@ $ kubectl config set-credentials default-admin \
$ kubectl config set-context default-system --cluster=default-cluster --user=default-admin $ kubectl config set-context default-system --cluster=default-cluster --user=default-admin
$ kubectl config use-context default-system $ kubectl config use-context default-system
``` ```
7. Check it:
1. Check it: ```
```ShellSession
kubectl version kubectl version
``` ```
## GlusterFS ## GlusterFS
GlusterFS is not deployed by the standard`cluster.yml` playbook, see the
GlusterFS is not deployed by the standard `cluster.yml` playbook, see the
[GlusterFS playbook documentation](../../network-storage/glusterfs/README.md) [GlusterFS playbook documentation](../../network-storage/glusterfs/README.md)
for instructions. for instructions.
Basically you will install Gluster as Basically you will install Gluster as
```ShellSession ```ShellSession
ansible-playbook --become -i inventory/$CLUSTER/hosts ./contrib/network-storage/glusterfs/glusterfs.yml $ ansible-playbook --become -i inventory/$CLUSTER/hosts ./contrib/network-storage/glusterfs/glusterfs.yml
``` ```
## What's next ## What's next
Try out your new Kubernetes cluster with the [Hello Kubernetes service](https://kubernetes.io/docs/tasks/access-application-cluster/service-access-application-cluster/). Try out your new Kubernetes cluster with the [Hello Kubernetes service](https://kubernetes.io/docs/tasks/access-application-cluster/service-access-application-cluster/).
## Appendix
### Migration from `number_of_k8s_nodes*` to `k8s_nodes`
If you currently have a cluster defined using the `number_of_k8s_nodes*` variables and wish
to migrate to the `k8s_nodes` style you can do it like so:
```ShellSession
$ terraform state list
module.compute.data.openstack_images_image_v2.gfs_image
module.compute.data.openstack_images_image_v2.vm_image
module.compute.openstack_compute_floatingip_associate_v2.k8s_master[0]
module.compute.openstack_compute_floatingip_associate_v2.k8s_node[0]
module.compute.openstack_compute_floatingip_associate_v2.k8s_node[1]
module.compute.openstack_compute_floatingip_associate_v2.k8s_node[2]
module.compute.openstack_compute_instance_v2.k8s_master[0]
module.compute.openstack_compute_instance_v2.k8s_node[0]
module.compute.openstack_compute_instance_v2.k8s_node[1]
module.compute.openstack_compute_instance_v2.k8s_node[2]
module.compute.openstack_compute_keypair_v2.k8s
module.compute.openstack_compute_servergroup_v2.k8s_etcd[0]
module.compute.openstack_compute_servergroup_v2.k8s_master[0]
module.compute.openstack_compute_servergroup_v2.k8s_node[0]
module.compute.openstack_networking_secgroup_rule_v2.bastion[0]
module.compute.openstack_networking_secgroup_rule_v2.egress[0]
module.compute.openstack_networking_secgroup_rule_v2.k8s
module.compute.openstack_networking_secgroup_rule_v2.k8s_allowed_remote_ips[0]
module.compute.openstack_networking_secgroup_rule_v2.k8s_allowed_remote_ips[1]
module.compute.openstack_networking_secgroup_rule_v2.k8s_allowed_remote_ips[2]
module.compute.openstack_networking_secgroup_rule_v2.k8s_master[0]
module.compute.openstack_networking_secgroup_rule_v2.worker[0]
module.compute.openstack_networking_secgroup_rule_v2.worker[1]
module.compute.openstack_networking_secgroup_rule_v2.worker[2]
module.compute.openstack_networking_secgroup_rule_v2.worker[3]
module.compute.openstack_networking_secgroup_rule_v2.worker[4]
module.compute.openstack_networking_secgroup_v2.bastion[0]
module.compute.openstack_networking_secgroup_v2.k8s
module.compute.openstack_networking_secgroup_v2.k8s_master
module.compute.openstack_networking_secgroup_v2.worker
module.ips.null_resource.dummy_dependency
module.ips.openstack_networking_floatingip_v2.k8s_master[0]
module.ips.openstack_networking_floatingip_v2.k8s_node[0]
module.ips.openstack_networking_floatingip_v2.k8s_node[1]
module.ips.openstack_networking_floatingip_v2.k8s_node[2]
module.network.openstack_networking_network_v2.k8s[0]
module.network.openstack_networking_router_interface_v2.k8s[0]
module.network.openstack_networking_router_v2.k8s[0]
module.network.openstack_networking_subnet_v2.k8s[0]
$ terraform state mv 'module.compute.openstack_compute_floatingip_associate_v2.k8s_node[0]' 'module.compute.openstack_compute_floatingip_associate_v2.k8s_nodes["1"]'
Move "module.compute.openstack_compute_floatingip_associate_v2.k8s_node[0]" to "module.compute.openstack_compute_floatingip_associate_v2.k8s_nodes[\"1\"]"
Successfully moved 1 object(s).
$ terraform state mv 'module.compute.openstack_compute_floatingip_associate_v2.k8s_node[1]' 'module.compute.openstack_compute_floatingip_associate_v2.k8s_nodes["2"]'
Move "module.compute.openstack_compute_floatingip_associate_v2.k8s_node[1]" to "module.compute.openstack_compute_floatingip_associate_v2.k8s_nodes[\"2\"]"
Successfully moved 1 object(s).
$ terraform state mv 'module.compute.openstack_compute_floatingip_associate_v2.k8s_node[2]' 'module.compute.openstack_compute_floatingip_associate_v2.k8s_nodes["3"]'
Move "module.compute.openstack_compute_floatingip_associate_v2.k8s_node[2]" to "module.compute.openstack_compute_floatingip_associate_v2.k8s_nodes[\"3\"]"
Successfully moved 1 object(s).
$ terraform state mv 'module.compute.openstack_compute_instance_v2.k8s_node[0]' 'module.compute.openstack_compute_instance_v2.k8s_node["1"]'
Move "module.compute.openstack_compute_instance_v2.k8s_node[0]" to "module.compute.openstack_compute_instance_v2.k8s_node[\"1\"]"
Successfully moved 1 object(s).
$ terraform state mv 'module.compute.openstack_compute_instance_v2.k8s_node[1]' 'module.compute.openstack_compute_instance_v2.k8s_node["2"]'
Move "module.compute.openstack_compute_instance_v2.k8s_node[1]" to "module.compute.openstack_compute_instance_v2.k8s_node[\"2\"]"
Successfully moved 1 object(s).
$ terraform state mv 'module.compute.openstack_compute_instance_v2.k8s_node[2]' 'module.compute.openstack_compute_instance_v2.k8s_node["3"]'
Move "module.compute.openstack_compute_instance_v2.k8s_node[2]" to "module.compute.openstack_compute_instance_v2.k8s_node[\"3\"]"
Successfully moved 1 object(s).
$ terraform state mv 'module.ips.openstack_networking_floatingip_v2.k8s_node[0]' 'module.ips.openstack_networking_floatingip_v2.k8s_node["1"]'
Move "module.ips.openstack_networking_floatingip_v2.k8s_node[0]" to "module.ips.openstack_networking_floatingip_v2.k8s_node[\"1\"]"
Successfully moved 1 object(s).
$ terraform state mv 'module.ips.openstack_networking_floatingip_v2.k8s_node[1]' 'module.ips.openstack_networking_floatingip_v2.k8s_node["2"]'
Move "module.ips.openstack_networking_floatingip_v2.k8s_node[1]" to "module.ips.openstack_networking_floatingip_v2.k8s_node[\"2\"]"
Successfully moved 1 object(s).
$ terraform state mv 'module.ips.openstack_networking_floatingip_v2.k8s_node[2]' 'module.ips.openstack_networking_floatingip_v2.k8s_node["3"]'
Move "module.ips.openstack_networking_floatingip_v2.k8s_node[2]" to "module.ips.openstack_networking_floatingip_v2.k8s_node[\"3\"]"
Successfully moved 1 object(s).
```
Of course for nodes without floating ips those steps can be omitted.

View File

@@ -1,108 +1,101 @@
provider "openstack" {
version = "~> 1.17"
}
module "network" { module "network" {
source = "./modules/network" source = "./modules/network"
external_net = var.external_net external_net = "${var.external_net}"
network_name = var.network_name network_name = "${var.network_name}"
subnet_cidr = var.subnet_cidr subnet_cidr = "${var.subnet_cidr}"
cluster_name = var.cluster_name cluster_name = "${var.cluster_name}"
dns_nameservers = var.dns_nameservers dns_nameservers = "${var.dns_nameservers}"
network_dns_domain = var.network_dns_domain network_dns_domain = "${var.network_dns_domain}"
use_neutron = var.use_neutron use_neutron = "${var.use_neutron}"
router_id = var.router_id
} }
module "ips" { module "ips" {
source = "./modules/ips" source = "./modules/ips"
number_of_k8s_masters = var.number_of_k8s_masters number_of_k8s_masters = "${var.number_of_k8s_masters}"
number_of_k8s_masters_no_etcd = var.number_of_k8s_masters_no_etcd number_of_k8s_masters_no_etcd = "${var.number_of_k8s_masters_no_etcd}"
number_of_k8s_nodes = var.number_of_k8s_nodes number_of_k8s_nodes = "${var.number_of_k8s_nodes}"
floatingip_pool = var.floatingip_pool floatingip_pool = "${var.floatingip_pool}"
number_of_bastions = var.number_of_bastions number_of_bastions = "${var.number_of_bastions}"
external_net = var.external_net external_net = "${var.external_net}"
network_name = var.network_name network_name = "${var.network_name}"
router_id = module.network.router_id router_id = "${module.network.router_id}"
k8s_nodes = var.k8s_nodes
k8s_master_fips = var.k8s_master_fips
router_internal_port_id = module.network.router_internal_port_id
} }
module "compute" { module "compute" {
source = "./modules/compute" source = "./modules/compute"
cluster_name = var.cluster_name cluster_name = "${var.cluster_name}"
az_list = var.az_list az_list = "${var.az_list}"
az_list_node = var.az_list_node number_of_k8s_masters = "${var.number_of_k8s_masters}"
number_of_k8s_masters = var.number_of_k8s_masters number_of_k8s_masters_no_etcd = "${var.number_of_k8s_masters_no_etcd}"
number_of_k8s_masters_no_etcd = var.number_of_k8s_masters_no_etcd number_of_etcd = "${var.number_of_etcd}"
number_of_etcd = var.number_of_etcd number_of_k8s_masters_no_floating_ip = "${var.number_of_k8s_masters_no_floating_ip}"
number_of_k8s_masters_no_floating_ip = var.number_of_k8s_masters_no_floating_ip number_of_k8s_masters_no_floating_ip_no_etcd = "${var.number_of_k8s_masters_no_floating_ip_no_etcd}"
number_of_k8s_masters_no_floating_ip_no_etcd = var.number_of_k8s_masters_no_floating_ip_no_etcd number_of_k8s_nodes = "${var.number_of_k8s_nodes}"
number_of_k8s_nodes = var.number_of_k8s_nodes number_of_bastions = "${var.number_of_bastions}"
number_of_bastions = var.number_of_bastions number_of_k8s_nodes_no_floating_ip = "${var.number_of_k8s_nodes_no_floating_ip}"
number_of_k8s_nodes_no_floating_ip = var.number_of_k8s_nodes_no_floating_ip number_of_gfs_nodes_no_floating_ip = "${var.number_of_gfs_nodes_no_floating_ip}"
number_of_gfs_nodes_no_floating_ip = var.number_of_gfs_nodes_no_floating_ip bastion_root_volume_size_in_gb = "${var.bastion_root_volume_size_in_gb}"
k8s_nodes = var.k8s_nodes etcd_root_volume_size_in_gb = "${var.etcd_root_volume_size_in_gb}"
bastion_root_volume_size_in_gb = var.bastion_root_volume_size_in_gb master_root_volume_size_in_gb = "${var.master_root_volume_size_in_gb}"
etcd_root_volume_size_in_gb = var.etcd_root_volume_size_in_gb node_root_volume_size_in_gb = "${var.node_root_volume_size_in_gb}"
master_root_volume_size_in_gb = var.master_root_volume_size_in_gb gfs_root_volume_size_in_gb = "${var.gfs_root_volume_size_in_gb}"
node_root_volume_size_in_gb = var.node_root_volume_size_in_gb gfs_volume_size_in_gb = "${var.gfs_volume_size_in_gb}"
gfs_root_volume_size_in_gb = var.gfs_root_volume_size_in_gb public_key_path = "${var.public_key_path}"
gfs_volume_size_in_gb = var.gfs_volume_size_in_gb image = "${var.image}"
master_volume_type = var.master_volume_type image_gfs = "${var.image_gfs}"
public_key_path = var.public_key_path ssh_user = "${var.ssh_user}"
image = var.image ssh_user_gfs = "${var.ssh_user_gfs}"
image_gfs = var.image_gfs flavor_k8s_master = "${var.flavor_k8s_master}"
ssh_user = var.ssh_user flavor_k8s_node = "${var.flavor_k8s_node}"
ssh_user_gfs = var.ssh_user_gfs flavor_etcd = "${var.flavor_etcd}"
flavor_k8s_master = var.flavor_k8s_master flavor_gfs_node = "${var.flavor_gfs_node}"
flavor_k8s_node = var.flavor_k8s_node network_name = "${var.network_name}"
flavor_etcd = var.flavor_etcd flavor_bastion = "${var.flavor_bastion}"
flavor_gfs_node = var.flavor_gfs_node k8s_master_fips = "${module.ips.k8s_master_fips}"
network_name = var.network_name k8s_master_no_etcd_fips = "${module.ips.k8s_master_no_etcd_fips}"
flavor_bastion = var.flavor_bastion k8s_node_fips = "${module.ips.k8s_node_fips}"
k8s_master_fips = module.ips.k8s_master_fips bastion_fips = "${module.ips.bastion_fips}"
k8s_master_no_etcd_fips = module.ips.k8s_master_no_etcd_fips bastion_allowed_remote_ips = "${var.bastion_allowed_remote_ips}"
k8s_node_fips = module.ips.k8s_node_fips master_allowed_remote_ips = "${var.master_allowed_remote_ips}"
k8s_nodes_fips = module.ips.k8s_nodes_fips k8s_allowed_remote_ips = "${var.k8s_allowed_remote_ips}"
bastion_fips = module.ips.bastion_fips k8s_allowed_egress_ips = "${var.k8s_allowed_egress_ips}"
bastion_allowed_remote_ips = var.bastion_allowed_remote_ips supplementary_master_groups = "${var.supplementary_master_groups}"
master_allowed_remote_ips = var.master_allowed_remote_ips supplementary_node_groups = "${var.supplementary_node_groups}"
k8s_allowed_remote_ips = var.k8s_allowed_remote_ips worker_allowed_ports = "${var.worker_allowed_ports}"
k8s_allowed_egress_ips = var.k8s_allowed_egress_ips wait_for_floatingip = "${var.wait_for_floatingip}"
supplementary_master_groups = var.supplementary_master_groups use_access_ip = "${var.use_access_ip}"
supplementary_node_groups = var.supplementary_node_groups use_server_groups = "${var.use_server_groups}"
master_allowed_ports = var.master_allowed_ports
worker_allowed_ports = var.worker_allowed_ports
wait_for_floatingip = var.wait_for_floatingip
use_access_ip = var.use_access_ip
use_server_groups = var.use_server_groups
extra_sec_groups = var.extra_sec_groups
extra_sec_groups_name = var.extra_sec_groups_name
network_id = module.network.router_id network_id = "${module.network.router_id}"
} }
output "private_subnet_id" { output "private_subnet_id" {
value = module.network.subnet_id value = "${module.network.subnet_id}"
} }
output "floating_network_id" { output "floating_network_id" {
value = var.external_net value = "${var.external_net}"
} }
output "router_id" { output "router_id" {
value = module.network.router_id value = "${module.network.router_id}"
} }
output "k8s_master_fips" { output "k8s_master_fips" {
value = concat(module.ips.k8s_master_fips, module.ips.k8s_master_no_etcd_fips) value = "${concat(module.ips.k8s_master_fips, module.ips.k8s_master_no_etcd_fips)}"
} }
output "k8s_node_fips" { output "k8s_node_fips" {
value = var.number_of_k8s_nodes > 0 ? module.ips.k8s_node_fips : [for key, value in module.ips.k8s_nodes_fips : value.address] value = "${module.ips.k8s_node_fips}"
} }
output "bastion_fips" { output "bastion_fips" {
value = module.ips.bastion_fips value = "${module.ips.bastion_fips}"
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,7 @@
variable "cluster_name" {} variable "cluster_name" {}
variable "az_list" { variable "az_list" {
type = list(string) type = "list"
}
variable "az_list_node" {
type = list(string)
} }
variable "number_of_k8s_masters" {} variable "number_of_k8s_masters" {}
@@ -38,8 +34,6 @@ variable "gfs_root_volume_size_in_gb" {}
variable "gfs_volume_size_in_gb" {} variable "gfs_volume_size_in_gb" {}
variable "master_volume_type" {}
variable "public_key_path" {} variable "public_key_path" {}
variable "image" {} variable "image" {}
@@ -67,43 +61,37 @@ variable "network_id" {
} }
variable "k8s_master_fips" { variable "k8s_master_fips" {
type = list type = "list"
} }
variable "k8s_master_no_etcd_fips" { variable "k8s_master_no_etcd_fips" {
type = list type = "list"
} }
variable "k8s_node_fips" { variable "k8s_node_fips" {
type = list type = "list"
}
variable "k8s_nodes_fips" {
type = map
} }
variable "bastion_fips" { variable "bastion_fips" {
type = list type = "list"
} }
variable "bastion_allowed_remote_ips" { variable "bastion_allowed_remote_ips" {
type = list type = "list"
} }
variable "master_allowed_remote_ips" { variable "master_allowed_remote_ips" {
type = list type = "list"
} }
variable "k8s_allowed_remote_ips" { variable "k8s_allowed_remote_ips" {
type = list type = "list"
} }
variable "k8s_allowed_egress_ips" { variable "k8s_allowed_egress_ips" {
type = list type = "list"
} }
variable "k8s_nodes" {}
variable "wait_for_floatingip" {} variable "wait_for_floatingip" {}
variable "supplementary_master_groups" { variable "supplementary_master_groups" {
@@ -114,24 +102,12 @@ variable "supplementary_node_groups" {
default = "" default = ""
} }
variable "master_allowed_ports" {
type = list
}
variable "worker_allowed_ports" { variable "worker_allowed_ports" {
type = list type = "list"
} }
variable "use_access_ip" {} variable "use_access_ip" {}
variable "use_server_groups" { variable "use_server_groups" {
type = bool type = bool
}
variable "extra_sec_groups" {
type = bool
}
variable "extra_sec_groups_name" {
type = string
} }

View File

@@ -1,8 +0,0 @@
terraform {
required_providers {
openstack = {
source = "terraform-provider-openstack/openstack"
}
}
required_version = ">= 0.12.26"
}

View File

@@ -1,41 +1,29 @@
resource "null_resource" "dummy_dependency" { resource "null_resource" "dummy_dependency" {
triggers = { triggers = {
dependency_id = var.router_id dependency_id = "${var.router_id}"
} }
depends_on = [
var.router_internal_port_id
]
} }
# If user specifies pre-existing IPs to use in k8s_master_fips, do not create new ones.
resource "openstack_networking_floatingip_v2" "k8s_master" { resource "openstack_networking_floatingip_v2" "k8s_master" {
count = length(var.k8s_master_fips) > 0 ? 0 : var.number_of_k8s_masters count = "${var.number_of_k8s_masters}"
pool = var.floatingip_pool pool = "${var.floatingip_pool}"
depends_on = [null_resource.dummy_dependency] depends_on = ["null_resource.dummy_dependency"]
} }
# If user specifies pre-existing IPs to use in k8s_master_fips, do not create new ones.
resource "openstack_networking_floatingip_v2" "k8s_master_no_etcd" { resource "openstack_networking_floatingip_v2" "k8s_master_no_etcd" {
count = length(var.k8s_master_fips) > 0 ? 0 : var.number_of_k8s_masters_no_etcd count = "${var.number_of_k8s_masters_no_etcd}"
pool = var.floatingip_pool pool = "${var.floatingip_pool}"
depends_on = [null_resource.dummy_dependency] depends_on = ["null_resource.dummy_dependency"]
} }
resource "openstack_networking_floatingip_v2" "k8s_node" { resource "openstack_networking_floatingip_v2" "k8s_node" {
count = var.number_of_k8s_nodes count = "${var.number_of_k8s_nodes}"
pool = var.floatingip_pool pool = "${var.floatingip_pool}"
depends_on = [null_resource.dummy_dependency] depends_on = ["null_resource.dummy_dependency"]
} }
resource "openstack_networking_floatingip_v2" "bastion" { resource "openstack_networking_floatingip_v2" "bastion" {
count = var.number_of_bastions count = "${var.number_of_bastions}"
pool = var.floatingip_pool pool = "${var.floatingip_pool}"
depends_on = [null_resource.dummy_dependency] depends_on = ["null_resource.dummy_dependency"]
} }
resource "openstack_networking_floatingip_v2" "k8s_nodes" {
for_each = var.number_of_k8s_nodes == 0 ? { for key, value in var.k8s_nodes : key => value if value.floating_ip } : {}
pool = var.floatingip_pool
depends_on = [null_resource.dummy_dependency]
}

View File

@@ -1,21 +1,15 @@
# If k8s_master_fips is already defined as input, keep the same value since new FIPs have not been created.
output "k8s_master_fips" { output "k8s_master_fips" {
value = length(var.k8s_master_fips) > 0 ? var.k8s_master_fips : openstack_networking_floatingip_v2.k8s_master[*].address value = "${openstack_networking_floatingip_v2.k8s_master[*].address}"
} }
# If k8s_master_fips is already defined as input, keep the same value since new FIPs have not been created.
output "k8s_master_no_etcd_fips" { output "k8s_master_no_etcd_fips" {
value = length(var.k8s_master_fips) > 0 ? var.k8s_master_fips : openstack_networking_floatingip_v2.k8s_master_no_etcd[*].address value = "${openstack_networking_floatingip_v2.k8s_master_no_etcd[*].address}"
} }
output "k8s_node_fips" { output "k8s_node_fips" {
value = openstack_networking_floatingip_v2.k8s_node[*].address value = "${openstack_networking_floatingip_v2.k8s_node[*].address}"
}
output "k8s_nodes_fips" {
value = openstack_networking_floatingip_v2.k8s_nodes
} }
output "bastion_fips" { output "bastion_fips" {
value = openstack_networking_floatingip_v2.bastion[*].address value = "${openstack_networking_floatingip_v2.bastion[*].address}"
} }

View File

@@ -14,10 +14,4 @@ variable "network_name" {}
variable "router_id" { variable "router_id" {
default = "" default = ""
} }
variable "k8s_nodes" {}
variable "k8s_master_fips" {}
variable "router_internal_port_id" {}

View File

@@ -1,11 +0,0 @@
terraform {
required_providers {
null = {
source = "hashicorp/null"
}
openstack = {
source = "terraform-provider-openstack/openstack"
}
}
required_version = ">= 0.12.26"
}

View File

@@ -1,33 +1,28 @@
resource "openstack_networking_router_v2" "k8s" { resource "openstack_networking_router_v2" "k8s" {
name = "${var.cluster_name}-router" name = "${var.cluster_name}-router"
count = var.use_neutron == 1 && var.router_id == null ? 1 : 0 count = "${var.use_neutron}"
admin_state_up = "true" admin_state_up = "true"
external_network_id = var.external_net external_network_id = "${var.external_net}"
}
data "openstack_networking_router_v2" "k8s" {
router_id = var.router_id
count = var.use_neutron == 1 && var.router_id != null ? 1 : 0
} }
resource "openstack_networking_network_v2" "k8s" { resource "openstack_networking_network_v2" "k8s" {
name = var.network_name name = "${var.network_name}"
count = var.use_neutron count = "${var.use_neutron}"
dns_domain = var.network_dns_domain != null ? var.network_dns_domain : null dns_domain = var.network_dns_domain != null ? "${var.network_dns_domain}" : null
admin_state_up = "true" admin_state_up = "true"
} }
resource "openstack_networking_subnet_v2" "k8s" { resource "openstack_networking_subnet_v2" "k8s" {
name = "${var.cluster_name}-internal-network" name = "${var.cluster_name}-internal-network"
count = var.use_neutron count = "${var.use_neutron}"
network_id = openstack_networking_network_v2.k8s[count.index].id network_id = "${openstack_networking_network_v2.k8s[count.index].id}"
cidr = var.subnet_cidr cidr = "${var.subnet_cidr}"
ip_version = 4 ip_version = 4
dns_nameservers = var.dns_nameservers dns_nameservers = "${var.dns_nameservers}"
} }
resource "openstack_networking_router_interface_v2" "k8s" { resource "openstack_networking_router_interface_v2" "k8s" {
count = var.use_neutron count = "${var.use_neutron}"
router_id = "%{if openstack_networking_router_v2.k8s != []}${openstack_networking_router_v2.k8s[count.index].id}%{else}${var.router_id}%{endif}" router_id = "${openstack_networking_router_v2.k8s[count.index].id}"
subnet_id = openstack_networking_subnet_v2.k8s[count.index].id subnet_id = "${openstack_networking_subnet_v2.k8s[count.index].id}"
} }

View File

@@ -1,11 +1,11 @@
output "router_id" { output "router_id" {
value = "%{if var.use_neutron == 1} ${var.router_id == null ? element(concat(openstack_networking_router_v2.k8s.*.id, [""]), 0) : var.router_id} %{else} %{endif}" value = "${element(concat(openstack_networking_router_v2.k8s.*.id, list("")), 0)}"
} }
output "router_internal_port_id" { output "router_internal_port_id" {
value = element(concat(openstack_networking_router_interface_v2.k8s.*.id, [""]), 0) value = "${element(concat(openstack_networking_router_interface_v2.k8s.*.id, list("")), 0)}"
} }
output "subnet_id" { output "subnet_id" {
value = element(concat(openstack_networking_subnet_v2.k8s.*.id, [""]), 0) value = "${element(concat(openstack_networking_subnet_v2.k8s.*.id, list("")), 0)}"
} }

View File

@@ -7,11 +7,9 @@ variable "network_dns_domain" {}
variable "cluster_name" {} variable "cluster_name" {}
variable "dns_nameservers" { variable "dns_nameservers" {
type = list type = "list"
} }
variable "subnet_cidr" {} variable "subnet_cidr" {}
variable "use_neutron" {} variable "use_neutron" {}
variable "router_id" {}

Some files were not shown because too many files have changed in this diff Show More