Compare commits

..

12 Commits

Author SHA1 Message Date
rptaylor
6f97687d19 Release 2.8 robust san handling (#4478)
* robust handling of API server SANs for 2.8 branch

* use apiserver_loadbalancer_domain_name if it is defined, according to PR 3977
2019-04-10 04:30:15 -07:00
Daniel Werdermann
447605ca0e Add oidc prefixes to kubeadm templates (#4462) 2019-04-09 01:07:06 -07:00
Bort Verwilst
3901480bc1 go to k8s 1.12.7 (#4400) 2019-03-28 06:20:46 -07:00
Rong Zhang
c42cb8f9b2 Merge pull request #4373 from prabdeb/prabdeb-fix-2.8-volume-mount-apiServer
Fixing volume mount issue for apiServerExtraVolumes in kubeadm-config.v1alpha2.yaml.j2
2019-03-27 14:59:45 +08:00
Prabal Deb (prabdeb)
5c28bb0679 Fixing volume issue 2019-03-20 21:34:44 +05:30
Bort Verwilst
6d53229986 Make 1.12.6 the default k8s release (#4306) 2019-03-04 00:38:56 -08:00
Xavi
1e57d2e21a [SECURITY] Docker patches for CVE-2019-5736 Ubuntu Bionic (#4267) 2019-02-19 03:19:36 -08:00
Bort Verwilst
ea41fc5e74 backport cve-2019-5736 to release-2.8 (#4234)
* [SECURITY] Docker patches for CVE-2019-5736 (#4223)

This updates docker 18.06 and 18.09 with the two patches released
yesterday to address the new runc exploit. Details here:
https://kubernetes.io/blog/2019/02/11/runc-and-cve-2019-5736/

* keep edge versions to same minor

* keep edge versions to same minor
2019-02-14 00:55:54 -08:00
Bort Verwilst
4167807f17 Upgrade to 1.12.5 (#4066) 2019-01-18 06:30:36 -08:00
Bort Verwilst
2ac1c7562f More Feature/2.8 backports for 2.8.1 (#3911)
* Move node-cidr-mask-size to ControllerManagerextraArgs (#3845)

* Fix apiServerCertSANs in kubeadm config file (#3839)

* Backport #3908

* Update kubernetes to 1.12.4
2018-12-25 21:43:03 -08:00
Bort Verwilst
2d6e31d281 Backport of fixes to release-2.8 for 2.8.1? (#3897)
* Fix assertion for alone etcd nodes (#3847)

* Fix error with ipvs on cluster reset task (#3848)

* Reset: Check for kube-ipvs0 presence before remove it (#3816)
2018-12-18 05:29:58 -08:00
Andreas Kruger
0a19d1bf01 Update current release in README 2018-12-03 20:04:31 +01:00
1000 changed files with 30940 additions and 27745 deletions

View File

@@ -1,27 +0,0 @@
---
parseable: true
skip_list:
# see https://docs.ansible.com/ansible-lint/rules/default_rules.html for a list of all default rules
# The following rules throw errors.
# 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:
#
# [E204]: "Lines should be no longer than 160 chars"
# This could be re-enabled with a major rewrite in the future.
# For now, there's not enough value gain from strictly limiting line length.
# (Disabled in May 2019)
- '204'
# [E701]: "meta/main.yml should contain relevant info"
# Roles in Kubespray are not intended to be used/imported by Ansible Galaxy.
# While it can be useful to have these metadata available, they are also available in the existing documentation.
# (Disabled in May 2019)
- '701'

View File

@@ -1,11 +1,16 @@
--- <!-- Thanks for filing an issue! Before hitting the button, please answer these questions.-->
name: Bug Report
about: Report a bug encountered while operating Kubernetes **Is this a BUG REPORT or FEATURE REQUEST?** (choose one):
labels: kind/bug
---
<!-- <!--
Please, be ready for followup questions, and please respond in a timely If this is a BUG REPORT, please:
- Fill in as much of the template below as you can. If you leave out
information, we can't help you as well.
If this is a FEATURE REQUEST, please:
- Describe *in detail* the feature/behavior/change you'd like to see.
In both cases, be ready for followup questions, and please respond in a timely
manner. If we can't reproduce a bug or think a feature already exists, we manner. If we can't reproduce a bug or think a feature already exists, we
might close your issue. If we're wrong, PLEASE feel free to reopen it and might close your issue. If we're wrong, PLEASE feel free to reopen it and
explain why. explain why.
@@ -18,8 +23,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 +30,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,11 +0,0 @@
---
name: Enhancement Request
about: Suggest an enhancement to the Kubespray project
labels: kind/feature
---
<!-- Please only use this template for submitting enhancement requests -->
**What would you like to be added**:
**Why is this needed**:

View File

@@ -1,20 +0,0 @@
---
name: Failing Test
about: Report test failures in Kubespray CI jobs
labels: kind/failing-test
---
<!-- Please only use this template for submitting reports about failing tests in Kubespray CI jobs -->
**Which jobs are failing**:
**Which test(s) are failing**:
**Since when has it been failing**:
**Testgrid link**:
**Reason for failure**:
**Anything else we need to know**:

View File

@@ -1,18 +0,0 @@
---
name: Support Request
about: Support request or question relating to Kubespray
labels: triage/support
---
<!--
STOP -- PLEASE READ!
GitHub is not the right place for support requests.
If you're looking for help, check [Stack Overflow](https://stackoverflow.com/questions/tagged/kubespray) and the [troubleshooting guide](https://kubernetes.io/docs/tasks/debug-application-cluster/troubleshooting/).
You can also post your question on the [Kubernetes Slack](http://slack.k8s.io/) or the [Discuss Kubernetes](https://discuss.kubernetes.io/) forum.
If the matter is security related, please disclose it privately via https://kubernetes.io/security/.
-->

View File

@@ -1,44 +0,0 @@
<!-- 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
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
3. Ensure you have added or ran the appropriate tests for your PR: https://git.k8s.io/community/contributors/devel/sig-testing/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
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
-->
**What type of PR is this?**
> Uncomment only one ` /kind <>` line, hit enter to put that in a new line, and remove leading whitespaces from that line:
>
> /kind api-change
> /kind bug
> /kind cleanup
> /kind design
> /kind documentation
> /kind failing-test
> /kind feature
> /kind flake
**What this PR does / why we need it**:
**Which issue(s) this PR fixes**:
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
-->
Fixes #
**Special notes for your reviewer**:
**Does this PR introduce a user-facing change?**:
<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
-->
```release-note
```

11
.gitignore vendored
View File

@@ -1,6 +1,9 @@
.vagrant .vagrant
*.retry *.retry
**/vagrant_ansible_inventory **/vagrant_ansible_inventory
inventory/credentials/
inventory/group_vars/fake_hosts.yml
inventory/host_vars/
temp temp
.idea .idea
.tox .tox
@@ -8,19 +11,12 @@ temp
*.bak *.bak
*.tfstate *.tfstate
*.tfstate.backup *.tfstate.backup
.terraform/
contrib/terraform/aws/credentials.tfvars contrib/terraform/aws/credentials.tfvars
/ssh-bastion.conf /ssh-bastion.conf
**/*.sw[pon] **/*.sw[pon]
*~ *~
vagrant/ vagrant/
# Ansible inventory
inventory/*
!inventory/local
!inventory/sample
inventory/*/artifacts/
# Byte-compiled / optimized / DLL files # Byte-compiled / optimized / DLL files
__pycache__/ __pycache__/
*.py[cod] *.py[cod]
@@ -28,6 +24,7 @@ __pycache__/
# Distribution / packaging # Distribution / packaging
.Python .Python
inventory/*/artifacts/
env/ env/
build/ build/
credentials/ credentials/

View File

@@ -1,16 +1,14 @@
---
stages: stages:
- unit-tests - unit-tests
- deploy-part1
- moderator - moderator
- deploy-part1
- deploy-part2 - deploy-part2
- deploy-part3
- deploy-special - deploy-special
variables: variables:
KUBESPRAY_VERSION: v2.12.9
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"
@@ -26,50 +24,726 @@ variables:
IDEMPOT_CHECK: "false" IDEMPOT_CHECK: "false"
RESET_CHECK: "false" RESET_CHECK: "false"
UPGRADE_TEST: "false" UPGRADE_TEST: "false"
MITOGEN_ENABLE: "false" KUBEADM_ENABLED: "false"
ANSIBLE_LOG_LEVEL: "-vv" LOG_LEVEL: "-vv"
RECOVER_CONTROL_PLANE_TEST: "false"
RECOVER_CONTROL_PLANE_TEST_GROUPS: "etcd[2:],kube-master[1:]" # asia-east1-a
# asia-northeast1-a
# europe-west1-b
# us-central1-a
# us-east1-b
# us-west1-a
before_script: before_script:
- ./tests/scripts/rebase.sh - /usr/bin/python -m pip install -r tests/requirements.txt
- update-alternatives --install /usr/bin/python python /usr/bin/python3 1 - mkdir -p /.ssh
- python -m pip install -r tests/requirements.txt
- mkdir -p /.ssh
.job: &job .job: &job
tags: tags:
- packet - kubernetes
image: quay.io/kubespray/kubespray:$KUBESPRAY_VERSION - docker
artifacts: image: quay.io/kubespray/kubespray:v2.7
paths:
- cluster-dump/ .docker_service: &docker_service
services:
- docker:dind
.create_cluster: &create_cluster
<<: *job
<<: *docker_service
.gce_variables: &gce_variables
GCE_USER: travis
SSH_USER: $GCE_USER
CLOUD_MACHINE_TYPE: "g1-small"
CI_PLATFORM: "gce"
PRIVATE_KEY: $GCE_PRIVATE_KEY
.do_variables: &do_variables
PRIVATE_KEY: $DO_PRIVATE_KEY
CI_PLATFORM: "do"
SSH_USER: root
.testcases: &testcases .testcases: &testcases
<<: *job <<: *job
<<: *docker_service
cache:
key: "$CI_BUILD_REF_NAME"
paths:
- downloads/
- $HOME/.cache
before_script: before_script:
- update-alternatives --install /usr/bin/python python /usr/bin/python3 1 - docker info
- ./tests/scripts/rebase.sh - /usr/bin/python -m pip install -r requirements.txt
- ./tests/scripts/testcases_prepare.sh - /usr/bin/python -m pip install -r tests/requirements.txt
- mkdir -p /.ssh
- mkdir -p $HOME/.ssh
- ansible-playbook --version
- export PYPATH=$([[ ! "$CI_JOB_NAME" =~ "coreos" ]] && echo /usr/bin/python || echo /opt/bin/python)
- echo "CI_JOB_NAME is $CI_JOB_NAME"
- echo "PYPATH is $PYPATH"
script: script:
- ./tests/scripts/testcases_run.sh - pwd
after_script: - ls
- chronic ./tests/scripts/testcases_cleanup.sh - echo ${PWD}
- echo "${STARTUP_SCRIPT}"
- cd tests && make create-${CI_PLATFORM} -s ; cd -
# Check out latest tag if testing upgrade
# Uncomment when gitlab kubespray repo has tags
#- test "${UPGRADE_TEST}" != "false" && git fetch --all && git checkout $(git describe --tags $(git rev-list --tags --max-count=1))
- test "${UPGRADE_TEST}" != "false" && git checkout 53d87e53c5899d4ea2904ab7e3883708dd6363d3
# Checkout the CI vars file so it is available
- test "${UPGRADE_TEST}" != "false" && git checkout "${CI_BUILD_REF}" tests/files/${CI_JOB_NAME}.yml
# Workaround https://github.com/kubernetes-sigs/kubespray/issues/2021
- 'sh -c "echo ignore_assert_errors: true | tee -a tests/files/${CI_JOB_NAME}.yml"'
# Create cluster
- >
ansible-playbook
-i ${ANSIBLE_INVENTORY}
-b --become-user=root
--private-key=${HOME}/.ssh/id_rsa
-u $SSH_USER
${SSH_ARGS}
${LOG_LEVEL}
-e @${CI_TEST_VARS}
-e ansible_ssh_user=${SSH_USER}
-e local_release_dir=${PWD}/downloads
--limit "all:!fake_hosts"
cluster.yml
# Repeat deployment if testing upgrade
- >
if [ "${UPGRADE_TEST}" != "false" ]; then
test "${UPGRADE_TEST}" == "basic" && PLAYBOOK="cluster.yml";
test "${UPGRADE_TEST}" == "graceful" && PLAYBOOK="upgrade-cluster.yml";
git checkout "${CI_BUILD_REF}";
ansible-playbook
-i ${ANSIBLE_INVENTORY}
-b --become-user=root
--private-key=${HOME}/.ssh/id_rsa
-u $SSH_USER
${SSH_ARGS}
${LOG_LEVEL}
-e @${CI_TEST_VARS}
-e ansible_ssh_user=${SSH_USER}
-e local_release_dir=${PWD}/downloads
--limit "all:!fake_hosts"
$PLAYBOOK;
fi
# Tests Cases
## Test Master API
- >
ansible-playbook -i ${ANSIBLE_INVENTORY} -e ansible_python_interpreter=${PYPATH} -u $SSH_USER -e ansible_ssh_user=$SSH_USER $SSH_ARGS -b --become-user=root --limit "all:!fake_hosts" tests/testcases/010_check-apiserver.yml $LOG_LEVEL
-e "{kubeadm_enabled: ${KUBEADM_ENABLED}}"
## Ping the between 2 pod
- ansible-playbook -i ${ANSIBLE_INVENTORY} -e ansible_python_interpreter=${PYPATH} -u $SSH_USER -e ansible_ssh_user=$SSH_USER $SSH_ARGS -b --become-user=root --limit "all:!fake_hosts" tests/testcases/030_check-network.yml $LOG_LEVEL
## Advanced DNS checks
- ansible-playbook -i ${ANSIBLE_INVENTORY} -e ansible_python_interpreter=${PYPATH} -u $SSH_USER -e ansible_ssh_user=$SSH_USER $SSH_ARGS -b --become-user=root --limit "all:!fake_hosts" tests/testcases/040_check-network-adv.yml $LOG_LEVEL
## Idempotency checks 1/5 (repeat deployment)
- >
if [ "${IDEMPOT_CHECK}" = "true" ]; then
ansible-playbook
-i ${ANSIBLE_INVENTORY}
-b --become-user=root
--private-key=${HOME}/.ssh/id_rsa
-u $SSH_USER
${SSH_ARGS}
${LOG_LEVEL}
-e @${CI_TEST_VARS}
-e ansible_python_interpreter=${PYPATH}
-e local_release_dir=${PWD}/downloads
--limit "all:!fake_hosts"
cluster.yml;
fi
## Idempotency checks 2/5 (Advanced DNS checks)
- >
if [ "${IDEMPOT_CHECK}" = "true" ]; then
ansible-playbook
-i ${ANSIBLE_INVENTORY}
-b --become-user=root
--private-key=${HOME}/.ssh/id_rsa
-u $SSH_USER
${SSH_ARGS}
${LOG_LEVEL}
-e @${CI_TEST_VARS}
--limit "all:!fake_hosts"
tests/testcases/040_check-network-adv.yml $LOG_LEVEL;
fi
## Idempotency checks 3/5 (reset deployment)
- >
if [ "${IDEMPOT_CHECK}" = "true" -a "${RESET_CHECK}" = "true" ]; then
ansible-playbook
-i ${ANSIBLE_INVENTORY}
-b --become-user=root
--private-key=${HOME}/.ssh/id_rsa
-u $SSH_USER
${SSH_ARGS}
${LOG_LEVEL}
-e @${CI_TEST_VARS}
-e ansible_python_interpreter=${PYPATH}
-e reset_confirmation=yes
--limit "all:!fake_hosts"
reset.yml;
fi
## Idempotency checks 4/5 (redeploy after reset)
- >
if [ "${IDEMPOT_CHECK}" = "true" -a "${RESET_CHECK}" = "true" ]; then
ansible-playbook
-i ${ANSIBLE_INVENTORY}
-b --become-user=root
--private-key=${HOME}/.ssh/id_rsa
-u $SSH_USER
${SSH_ARGS}
${LOG_LEVEL}
-e @${CI_TEST_VARS}
-e ansible_python_interpreter=${PYPATH}
-e local_release_dir=${PWD}/downloads
--limit "all:!fake_hosts"
cluster.yml;
fi
## Idempotency checks 5/5 (Advanced DNS checks)
- >
if [ "${IDEMPOT_CHECK}" = "true" -a "${RESET_CHECK}" = "true" ]; then
ansible-playbook -i ${ANSIBLE_INVENTORY} -e ansible_python_interpreter=${PYPATH}
-u $SSH_USER -e ansible_ssh_user=$SSH_USER $SSH_ARGS -b --become-user=root
--limit "all:!fake_hosts"
tests/testcases/040_check-network-adv.yml $LOG_LEVEL;
fi
after_script:
- cd tests && make delete-${CI_PLATFORM} -s ; cd -
.gce: &gce
<<: *testcases
variables:
<<: *gce_variables
.do: &do
variables:
<<: *do_variables
<<: *testcases
# Test matrix. Leave the comments for markup scripts.
.coreos_calico_aio_variables: &coreos_calico_aio_variables
# stage: deploy-part1
MOVED_TO_GROUP_VARS: "true"
.ubuntu18_flannel_aio_variables: &ubuntu18_flannel_aio_variables
# stage: deploy-part1
MOVED_TO_GROUP_VARS: "true"
.centos_weave_kubeadm_variables: &centos_weave_kubeadm_variables
# stage: deploy-part1
UPGRADE_TEST: "graceful"
.ubuntu_canal_kubeadm_variables: &ubuntu_canal_kubeadm_variables
# stage: deploy-part1
MOVED_TO_GROUP_VARS: "true"
.ubuntu_canal_ha_variables: &ubuntu_canal_ha_variables
# stage: deploy-special
MOVED_TO_GROUP_VARS: "true"
.ubuntu_contiv_sep_variables: &ubuntu_contiv_sep_variables
# stage: deploy-special
MOVED_TO_GROUP_VARS: "true"
.coreos_cilium_variables: &coreos_cilium_variables
# stage: deploy-special
MOVED_TO_GROUP_VARS: "true"
.ubuntu_cilium_sep_variables: &ubuntu_cilium_sep_variables
# stage: deploy-special
MOVED_TO_GROUP_VARS: "true"
.rhel7_weave_variables: &rhel7_weave_variables
# stage: deploy-part1
MOVED_TO_GROUP_VARS: "true"
.centos7_flannel_addons_variables: &centos7_flannel_addons_variables
# stage: deploy-part2
MOVED_TO_GROUP_VARS: "true"
.debian9_calico_variables: &debian9_calico_variables
# stage: deploy-part2
MOVED_TO_GROUP_VARS: "true"
.coreos_canal_variables: &coreos_canal_variables
# stage: deploy-part2
MOVED_TO_GROUP_VARS: "true"
.rhel7_canal_sep_variables: &rhel7_canal_sep_variables
# stage: deploy-special
MOVED_TO_GROUP_VARS: "true"
.ubuntu_weave_sep_variables: &ubuntu_weave_sep_variables
# stage: deploy-special
MOVED_TO_GROUP_VARS: "true"
.centos7_calico_ha_variables: &centos7_calico_ha_variables
# stage: deploy-special
MOVED_TO_GROUP_VARS: "true"
.centos7_kube_router_variables: &centos7_kube_router_variables
# stage: deploy-special
MOVED_TO_GROUP_VARS: "true"
.centos7_multus_calico_variables: &centos7_multus_calico_variables
# stage: deploy-part2
UPGRADE_TEST: "graceful"
.coreos_alpha_weave_ha_variables: &coreos_alpha_weave_ha_variables
# stage: deploy-special
MOVED_TO_GROUP_VARS: "true"
.coreos_kube_router_variables: &coreos_kube_router_variables
# stage: deploy-special
MOVED_TO_GROUP_VARS: "true"
.ubuntu_rkt_sep_variables: &ubuntu_rkt_sep_variables
# stage: deploy-part1
MOVED_TO_GROUP_VARS: "true"
.ubuntu_flannel_variables: &ubuntu_flannel_variables
# stage: deploy-part2
MOVED_TO_GROUP_VARS: "true"
.ubuntu_kube_router_variables: &ubuntu_kube_router_variables
# stage: deploy-special
MOVED_TO_GROUP_VARS: "true"
.opensuse_canal_variables: &opensuse_canal_variables
# stage: deploy-part2
MOVED_TO_GROUP_VARS: "true"
# Builds for PRs only (premoderated by unit-tests step) and triggers (auto)
### PR JOBS PART1
gce_ubuntu18-flannel-aio:
stage: deploy-part1
<<: *job
<<: *gce
variables:
<<: *ubuntu18_flannel_aio_variables
<<: *gce_variables
when: on_success
except: ['triggers']
only: [/^pr-.*$/]
### PR JOBS PART2
gce_coreos-calico-aio:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *coreos_calico_aio_variables
<<: *gce_variables
when: on_success
except: ['triggers']
only: [/^pr-.*$/]
gce_centos7-flannel-addons:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *centos7_flannel_addons_variables
when: on_success
except: ['triggers']
only: [/^pr-.*$/]
gce_centos-weave-kubeadm-sep:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *centos_weave_kubeadm_variables
when: on_success
except: ['triggers']
only: [/^pr-.*$/]
gce_ubuntu-flannel-ha:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *ubuntu_flannel_variables
when: on_success
except: ['triggers']
only: [/^pr-.*$/]
### MANUAL JOBS
gce_ubuntu-weave-sep:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *ubuntu_weave_sep_variables
when: manual
except: ['triggers']
only: [/^pr-.*$/]
gce_coreos-calico-sep-triggers:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *coreos_calico_aio_variables
when: on_success
only: ['triggers']
gce_ubuntu-canal-ha-triggers:
stage: deploy-special
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *ubuntu_canal_ha_variables
when: on_success
only: ['triggers']
gce_centos7-flannel-addons-triggers:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *centos7_flannel_addons_variables
when: on_success
only: ['triggers']
gce_ubuntu-weave-sep-triggers:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *ubuntu_weave_sep_variables
when: on_success
only: ['triggers']
# More builds for PRs/merges (manual) and triggers (auto)
do_ubuntu-canal-ha:
stage: deploy-part2
<<: *job
<<: *do
variables:
<<: *do_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_ubuntu-canal-ha:
stage: deploy-special
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *ubuntu_canal_ha_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_ubuntu-canal-kubeadm:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *ubuntu_canal_kubeadm_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_ubuntu-canal-kubeadm-triggers:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *ubuntu_canal_kubeadm_variables
when: on_success
only: ['triggers']
gce_centos-weave-kubeadm-triggers:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *centos_weave_kubeadm_variables
when: on_success
only: ['triggers']
gce_ubuntu-contiv-sep:
stage: deploy-special
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *ubuntu_contiv_sep_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_coreos-cilium:
stage: deploy-special
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *coreos_cilium_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_ubuntu-cilium-sep:
stage: deploy-special
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *ubuntu_cilium_sep_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_rhel7-weave:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *rhel7_weave_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_rhel7-weave-triggers:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *rhel7_weave_variables
when: on_success
only: ['triggers']
gce_debian9-calico-upgrade:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *debian9_calico_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_debian9-calico-triggers:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *debian9_calico_variables
when: on_success
only: ['triggers']
gce_coreos-canal:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *coreos_canal_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_coreos-canal-triggers:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *coreos_canal_variables
when: on_success
only: ['triggers']
gce_rhel7-canal-sep:
stage: deploy-special
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *rhel7_canal_sep_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_rhel7-canal-sep-triggers:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *rhel7_canal_sep_variables
when: on_success
only: ['triggers']
gce_centos7-calico-ha:
stage: deploy-special
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *centos7_calico_ha_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_centos7-calico-ha-triggers:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *centos7_calico_ha_variables
when: on_success
only: ['triggers']
gce_centos7-kube-router:
stage: deploy-special
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *centos7_kube_router_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_centos7-multus-calico:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *centos7_multus_calico_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_opensuse-canal:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *opensuse_canal_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
# no triggers yet https://github.com/kubernetes-incubator/kargo/issues/613
gce_coreos-alpha-weave-ha:
stage: deploy-special
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *coreos_alpha_weave_ha_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_coreos-kube-router:
stage: deploy-special
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *coreos_kube_router_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_ubuntu-rkt-sep:
stage: deploy-part2
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *ubuntu_rkt_sep_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
gce_ubuntu-kube-router-sep:
stage: deploy-special
<<: *job
<<: *gce
variables:
<<: *gce_variables
<<: *ubuntu_kube_router_variables
when: manual
except: ['triggers']
only: ['master', /^pr-.*$/]
# For failfast, at least 1 job must be defined in .gitlab-ci.yml
# Premoderated with manual actions # Premoderated with manual actions
ci-authorized: ci-authorized:
extends: .job <<: *job
stage: moderator stage: moderator
before_script:
- apt-get -y install jq
script: script:
- /bin/sh scripts/premoderator.sh - /bin/sh scripts/premoderator.sh
except: ['triggers', 'master'] except: ['triggers', 'master']
# Disable ci moderator
only: []
include: syntax-check:
- .gitlab-ci/lint.yml <<: *job
- .gitlab-ci/shellcheck.yml stage: unit-tests
- .gitlab-ci/terraform.yml script:
- .gitlab-ci/packet.yml - ansible-playbook -i inventory/local-tests.cfg -u root -e ansible_ssh_user=root -b --become-user=root cluster.yml -vvv --syntax-check
- .gitlab-ci/vagrant.yml - ansible-playbook -i inventory/local-tests.cfg -u root -e ansible_ssh_user=root -b --become-user=root upgrade-cluster.yml -vvv --syntax-check
- ansible-playbook -i inventory/local-tests.cfg -u root -e ansible_ssh_user=root -b --become-user=root reset.yml -vvv --syntax-check
- ansible-playbook -i inventory/local-tests.cfg -u root -e ansible_ssh_user=root -b --become-user=root extra_playbooks/upgrade-only-k8s.yml -vvv --syntax-check
except: ['triggers', 'master']
yamllint:
<<: *job
stage: unit-tests
script:
- yamllint roles
except: ['triggers', 'master']
tox-inventory-builder:
stage: unit-tests
<<: *job
script:
- pip install tox
- cd contrib/inventory_builder && tox
when: manual
except: ['triggers', 'master']

View File

@@ -1,76 +0,0 @@
---
yamllint:
extends: .job
stage: unit-tests
tags: [light]
variables:
LANG: C.UTF-8
script:
- yamllint --strict .
except: ['triggers', 'master']
vagrant-validate:
extends: .job
stage: unit-tests
tags: [light]
variables:
VAGRANT_VERSION: 2.2.4
script:
- ./tests/scripts/vagrant-validate.sh
except: ['triggers', 'master']
ansible-lint:
extends: .job
stage: unit-tests
tags: [light]
# lint every yml/yaml file that looks like it contains Ansible plays
script: |-
grep -Rl '^- hosts: \|^ hosts: ' --include \*.yml --include \*.yaml . | xargs -P 4 -n 25 ansible-lint -v
except: ['triggers', 'master']
syntax-check:
extends: .job
stage: unit-tests
tags: [light]
variables:
ANSIBLE_INVENTORY: inventory/local-tests.cfg
ANSIBLE_REMOTE_USER: root
ANSIBLE_BECOME: "true"
ANSIBLE_BECOME_USER: root
ANSIBLE_VERBOSITY: "3"
script:
- ansible-playbook --syntax-check cluster.yml
- ansible-playbook --syntax-check upgrade-cluster.yml
- ansible-playbook --syntax-check reset.yml
- ansible-playbook --syntax-check extra_playbooks/upgrade-only-k8s.yml
except: ['triggers', 'master']
tox-inventory-builder:
stage: unit-tests
tags: [light]
extends: .job
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
script:
- pip3 install tox
- cd contrib/inventory_builder && tox
except: ['triggers', 'master']
markdownlint:
stage: unit-tests
tags: [light]
image: node
before_script:
- npm install -g markdownlint-cli
script:
- 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,209 +0,0 @@
---
.packet: &packet
extends: .testcases
variables:
CI_PLATFORM: "packet"
SSH_USER: "kubespray"
tags:
- packet
only: [/^pr-.*$/]
except: ['triggers']
packet_ubuntu18-calico-aio:
stage: deploy-part1
extends: .packet
when: on_success
# Future AIO job
packet_ubuntu20-calico-aio:
stage: deploy-part1
extends: .packet
when: manual
# ### PR JOBS PART2
packet_centos7-flannel-containerd-addons-ha:
extends: .packet
stage: deploy-part2
when: on_success
variables:
MITOGEN_ENABLE: "true"
packet_centos7-crio:
extends: .packet
stage: deploy-part2
when: on_success
variables:
MITOGEN_ENABLE: "true"
packet_ubuntu18-crio:
extends: .packet
stage: deploy-part2
when: manual
variables:
MITOGEN_ENABLE: "true"
packet_ubuntu16-canal-kubeadm-ha:
stage: deploy-part2
extends: .packet
when: on_success
packet_ubuntu16-canal-sep:
stage: deploy-special
extends: .packet
when: manual
packet_ubuntu16-flannel-ha:
stage: deploy-part2
extends: .packet
when: manual
packet_ubuntu16-kube-router-sep:
stage: deploy-part2
extends: .packet
when: manual
packet_debian10-containerd:
stage: deploy-part2
extends: .packet
when: on_success
variables:
MITOGEN_ENABLE: "true"
packet_centos7-calico-ha-once-localhost:
stage: deploy-part2
extends: .packet
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
when: on_success
packet_centos8-calico:
stage: deploy-part2
extends: .packet
when: on_success
packet_fedora30-weave:
stage: deploy-part2
extends: .packet
when: on_success
packet_opensuse-canal:
stage: deploy-part2
extends: .packet
when: on_success
# Contiv does not work in k8s v1.16
# packet_ubuntu16-contiv-sep:
# stage: deploy-part2
# extends: .packet
# when: on_success
# ### MANUAL JOBS
packet_ubuntu16-weave-sep:
stage: deploy-part2
extends: .packet
when: manual
packet_ubuntu18-cilium-sep:
stage: deploy-special
extends: .packet
when: manual
packet_ubuntu18-flannel-containerd-ha:
stage: deploy-part2
extends: .packet
when: manual
packet_ubuntu18-flannel-containerd-ha-once:
stage: deploy-part2
extends: .packet
when: manual
packet_debian9-macvlan:
stage: deploy-part2
extends: .packet
when: manual
packet_centos7-calico-ha:
stage: deploy-part2
extends: .packet
when: manual
packet_centos7-kube-router:
stage: deploy-part2
extends: .packet
when: manual
packet_centos7-multus-calico:
stage: deploy-part2
extends: .packet
when: manual
packet_oracle7-canal-ha:
stage: deploy-part2
extends: .packet
when: manual
packet_fedora31-flannel:
stage: deploy-part2
extends: .packet
when: on_success
variables:
MITOGEN_ENABLE: "true"
packet_amazon-linux-2-aio:
stage: deploy-part2
extends: .packet
when: manual
# ### PR JOBS PART3
# Long jobs (45min+)
packet_centos7-weave-upgrade-ha:
stage: deploy-part3
extends: .packet
when: manual
variables:
UPGRADE_TEST: basic
MITOGEN_ENABLE: "false"
packet_debian9-calico-upgrade:
stage: deploy-part3
extends: .packet
when: manual
variables:
UPGRADE_TEST: graceful
MITOGEN_ENABLE: "false"
packet_debian9-calico-upgrade-once:
stage: deploy-part3
extends: .packet
when: manual
variables:
UPGRADE_TEST: graceful
MITOGEN_ENABLE: "false"
packet_ubuntu18-calico-ha-recover:
stage: deploy-part3
extends: .packet
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
when: on_success
variables:
RECOVER_CONTROL_PLANE_TEST: "true"
RECOVER_CONTROL_PLANE_TEST_GROUPS: "etcd[1:],kube-master[1:]"

View File

@@ -1,16 +0,0 @@
---
shellcheck:
extends: .job
stage: unit-tests
tags: [light]
variables:
SHELLCHECK_VERSION: v0.6.0
before_script:
- ./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
- cp shellcheck-"${SHELLCHECK_VERSION}"/shellcheck /usr/bin/
- shellcheck --version
script:
# Run shellcheck for all *.sh except contrib/
- find . -name '*.sh' -not -path './contrib/*' | xargs shellcheck --severity error
except: ['triggers', 'master']

View File

@@ -1,177 +0,0 @@
---
# Tests for contrib/terraform/
.terraform_install:
extends: .job
before_script:
- update-alternatives --install /usr/bin/python python /usr/bin/python3 1
- ./tests/scripts/rebase.sh
- ./tests/scripts/testcases_prepare.sh
- ./tests/scripts/terraform_install.sh
# Set Ansible config
- cp ansible.cfg ~/.ansible.cfg
# Prepare inventory
- cp contrib/terraform/$PROVIDER/sample-inventory/cluster.tfvars .
- ln -s contrib/terraform/$PROVIDER/hosts
- terraform init contrib/terraform/$PROVIDER
# Copy SSH keypair
- mkdir -p ~/.ssh
- echo "$PACKET_PRIVATE_KEY" | base64 -d > ~/.ssh/id_rsa
- chmod 400 ~/.ssh/id_rsa
- echo "$PACKET_PUBLIC_KEY" | base64 -d > ~/.ssh/id_rsa.pub
.terraform_validate:
extends: .terraform_install
stage: unit-tests
tags: [light]
only: ['master', /^pr-.*$/]
script:
- terraform validate -var-file=cluster.tfvars contrib/terraform/$PROVIDER
- terraform fmt -check -diff contrib/terraform/$PROVIDER
.terraform_apply:
extends: .terraform_install
tags: [light]
stage: deploy-part3
when: manual
only: [/^pr-.*$/]
artifacts:
paths:
- cluster-dump/
variables:
ANSIBLE_INVENTORY_UNPARSED_FAILED: "true"
ANSIBLE_INVENTORY: hosts
CI_PLATFORM: tf
TF_VAR_ssh_user: $SSH_USER
TF_VAR_cluster_name: $CI_JOB_ID
script:
- tests/scripts/testcases_run.sh
after_script:
# Cleanup regardless of exit code
- chronic ./tests/scripts/testcases_cleanup.sh
tf-validate-openstack:
extends: .terraform_validate
variables:
TF_VERSION: 0.12.24
PROVIDER: openstack
CLUSTER: $CI_COMMIT_REF_NAME
tf-validate-packet:
extends: .terraform_validate
variables:
TF_VERSION: 0.12.24
PROVIDER: packet
CLUSTER: $CI_COMMIT_REF_NAME
tf-validate-aws:
extends: .terraform_validate
variables:
TF_VERSION: 0.12.24
PROVIDER: aws
CLUSTER: $CI_COMMIT_REF_NAME
# tf-packet-ubuntu16-default:
# extends: .terraform_apply
# variables:
# TF_VERSION: 0.12.24
# PROVIDER: packet
# CLUSTER: $CI_COMMIT_REF_NAME
# TF_VAR_number_of_k8s_masters: "1"
# TF_VAR_number_of_k8s_nodes: "1"
# TF_VAR_plan_k8s_masters: t1.small.x86
# TF_VAR_plan_k8s_nodes: t1.small.x86
# TF_VAR_facility: ewr1
# TF_VAR_public_key_path: ""
# TF_VAR_operating_system: ubuntu_16_04
#
# tf-packet-ubuntu18-default:
# extends: .terraform_apply
# variables:
# TF_VERSION: 0.12.24
# PROVIDER: packet
# CLUSTER: $CI_COMMIT_REF_NAME
# TF_VAR_number_of_k8s_masters: "1"
# TF_VAR_number_of_k8s_nodes: "1"
# TF_VAR_plan_k8s_masters: t1.small.x86
# TF_VAR_plan_k8s_nodes: t1.small.x86
# TF_VAR_facility: ams1
# TF_VAR_public_key_path: ""
# 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"
# tf-ovh_cleanup:
# stage: unit-tests
# tags: [light]
# image: python
# 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
# variables:
# <<: *ovh_variables
# TF_VERSION: 0.12.24
# 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"]'
# tf-ovh_coreos-calico:
# extends: .terraform_apply
# when: on_success
# variables:
# <<: *ovh_variables
# TF_VERSION: 0.12.24
# PROVIDER: openstack
# CLUSTER: $CI_COMMIT_REF_NAME
# ANSIBLE_TIMEOUT: "60"
# SSH_USER: core
# 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: "4d4fd037-9493-4f2b-9afe-b542b5248eac" # b2-7
# TF_VAR_flavor_k8s_node: "4d4fd037-9493-4f2b-9afe-b542b5248eac" # b2-7
# TF_VAR_image: "CoreOS Stable"
# TF_VAR_k8s_allowed_remote_ips: '["0.0.0.0/0"]'

View File

@@ -1,49 +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: "kubespray"
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:
- vagrant up
after_script:
- vagrant destroy --force
vagrant_ubuntu18-flannel:
stage: deploy-part2
extends: .vagrant
when: on_success
vagrant_ubuntu18-weave-medium:
stage: deploy-part2
extends: .vagrant
when: manual

View File

@@ -1,2 +0,0 @@
---
MD013: false

1
CNAME
View File

@@ -1 +0,0 @@
kubespray.io

View File

@@ -2,30 +2,9 @@
## 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 `./tests/scripts/ansible-lint.sh`
#### 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. Submit a pull request.
5. Submit a pull request.

View File

@@ -1,21 +1,16 @@
FROM ubuntu:18.04 FROM ubuntu:16.04
RUN mkdir /kubespray RUN mkdir /kubespray
WORKDIR /kubespray WORKDIR /kubespray
RUN apt update -y && \ RUN apt update -y && \
apt install -y \ apt install -y \
libssl-dev python3-dev sshpass apt-transport-https jq moreutils \ libssl-dev python-dev sshpass apt-transport-https \
ca-certificates curl gnupg2 software-properties-common python3-pip rsync ca-certificates curl gnupg2 software-properties-common python-pip
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/python -m pip install pip -U && /usr/bin/python -m pip install -r tests/requirements.txt && python -m pip install -r requirements.txt
RUN curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.17.5/bin/linux/amd64/kubectl \
&& chmod a+x kubectl && cp kubectl /usr/local/bin/kubectl
# Some tools like yamllint need this
ENV LANG=C.UTF-8

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

3
OWNERS
View File

@@ -1,4 +1,5 @@
# See the OWNERS docs at https://go.k8s.io/owners # See the OWNERS file documentation:
# https://github.com/kubernetes/community/blob/master/contributors/guide/owners.md
approvers: approvers:
- kubespray-approvers - kubespray-approvers

View File

@@ -4,16 +4,15 @@ aliases:
- mattymo - mattymo
- atoms - atoms
- chadswen - chadswen
- mirwan - rsmitty
- miouge1 - bogdando
- riverzhang - bradbeam
- verwilst
- woopstar - woopstar
- luckysb - riverzhang
- holser
- smana
kubespray-reviewers: kubespray-reviewers:
- jjungnickel - jjungnickel
- archifleks - archifleks
- holmsten - chapsuk
- bozzo - mirwan
- floryut
- eppo

273
README.md
View File

@@ -1,53 +1,58 @@
# Deploy a Production Ready Kubernetes Cluster
![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**. Deploy a Production Ready Kubernetes Cluster
============================================
If you have questions, 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, GCE, Azure, OpenStack, vSphere, Packet (bare metal), Oracle Cloud Infrastructure (Experimental), or Baremetal** - Can be deployed on **AWS, GCE, Azure, OpenStack, vSphere, 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**
- **Continuous integration tests** - **Continuous integration tests**
## Quick Start Quick Start
-----------
To deploy the cluster you can use : To deploy the cluster you can use :
### Current release
2.8.2
### Ansible ### Ansible
#### Ansible version
Ansible v2.7.0 is failing and/or produce unexpected results due to [ansible/ansible/issues/46600](https://github.com/ansible/ansible/issues/46600)
#### Usage #### Usage
```ShellSession # Install dependencies from ``requirements.txt``
# Install dependencies from ``requirements.txt`` sudo pip install -r requirements.txt
sudo pip3 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/hosts.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
cat inventory/mycluster/group_vars/k8s-cluster/k8s-cluster.yml cat inventory/mycluster/group_vars/k8s-cluster/k8s-cluster.yml
# Deploy Kubespray with Ansible Playbook - run the playbook as root # Deploy Kubespray with Ansible Playbook - run the playbook as root
# The option `--become` is required, as for example writing SSL keys in /etc/, # The option `-b` 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 -b the playbook will fail to run!
ansible-playbook -i inventory/mycluster/hosts.yaml --become --become-user=root cluster.yml ansible-playbook -i inventory/mycluster/hosts.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).
As a consequence, `ansible-playbook` command will fail with: As a consequence, `ansible-playbook` command will fail with:
```
```raw
ERROR! no action detected in task. This often indicates a misspelled module name, or incorrect module path. ERROR! no action detected in task. This often indicates a misspelled module name, or incorrect module path.
``` ```
probably pointing on a task depending on a module present in requirements.txt (i.e. "unseal vault"). probably pointing on a task depending on a module present in requirements.txt (i.e. "unseal vault").
One way of solving this would be to uninstall the Ansible package and then, to install it via pip but it is not always possible. One way of solving this would be to uninstall the Ansible package and then, to install it via pip but it is not always possible.
@@ -58,158 +63,148 @@ A workaround consists of setting `ANSIBLE_LIBRARY` and `ANSIBLE_MODULE_UTILS` en
For Vagrant we need to install python dependencies for provisioning tasks. For Vagrant we need to install python dependencies for provisioning tasks.
Check if Python and pip are installed: Check if Python and pip are installed:
```ShellSession python -V && pip -V
python -V && pip -V
```
If this returns the version of the software, you're good to go. If not, download and install Python from here <https://www.python.org/downloads/source/> If this returns the version of the software, you're good to go. If not, download and install Python from here <https://www.python.org/downloads/source/>
Install the necessary requirements Install the necessary requirements
```ShellSession sudo pip install -r requirements.txt
sudo pip install -r requirements.txt vagrant up
vagrant up
```
## Documents Documents
---------
- [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)
- [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)
- [DNS stack](docs/dns-stack.md) - [DNS stack](docs/dns-stack.md)
- [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)
- [CoreOS bootstrap](docs/coreos.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) - [Cloud providers](docs/cloud.md)
- [Cloud providers](docs/cloud.md) - [OpenStack](docs/openstack.md)
- [OpenStack](docs/openstack.md) - [AWS](docs/aws.md)
- [AWS](docs/aws.md) - [Azure](docs/azure.md)
- [Azure](docs/azure.md) - [vSphere](docs/vsphere.md)
- [vSphere](docs/vsphere.md) - [Large deployments](docs/large-deployments.md)
- [Packet Host](docs/packet.md) - [Upgrades basics](docs/upgrades.md)
- [Large deployments](docs/large-deployments.md) - [Roadmap](docs/roadmap.md)
- [Adding/replacing a node](docs/nodes.md)
- [Upgrades basics](docs/upgrades.md)
- [Roadmap](docs/roadmap.md)
## Supported Linux Distributions Supported Linux Distributions
-----------------------------
- **Container Linux by CoreOS** - **Container Linux by CoreOS**
- **Debian** Buster, Jessie, Stretch, Wheezy - **Debian** Buster, Jessie, Stretch, Wheezy
- **Ubuntu** 16.04, 18.04 - **Ubuntu** 16.04, 18.04
- **CentOS/RHEL** 7, 8 (experimental: see [centos 8 notes](docs/centos8.md) - **CentOS/RHEL** 7
- **Fedora** 30, 31 - **Fedora** 28
- **Fedora CoreOS** (experimental: see [fcos Note](docs/fcos.md)) - **Fedora/CentOS** Atomic
- **openSUSE** Leap 42.3/Tumbleweed - **openSUSE** Leap 42.3/Tumbleweed
- **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.17.12 - [kubernetes](https://github.com/kubernetes/kubernetes) v1.12.7
- [etcd](https://github.com/coreos/etcd) v3.3.12 - [etcd](https://github.com/coreos/etcd) v3.2.24
- [docker](https://www.docker.com/) v18.06 (see note) - [docker](https://www.docker.com/) v18.06 (see note)
- [containerd](https://containerd.io/) v1.2.13 - [rkt](https://github.com/rkt/rkt) v1.21.0 (see Note 2)
- [cri-o](http://cri-o.io/) v1.17 (experimental: see [CRI-O Note](docs/cri-o.md). Only on fedora, ubuntu and centos based OS) - [cri-o](http://cri-o.io/) v1.11.5 (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.8.6 - [calico](https://github.com/projectcalico/calico) v3.1.3
- [calico](https://github.com/projectcalico/calico) v3.13.2 - [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.3.0
- [cilium](https://github.com/cilium/cilium) v1.7.2 - [contiv](https://github.com/contiv/install) v1.2.1
- [contiv](https://github.com/contiv/install) v1.2.1 - [flanneld](https://github.com/coreos/flannel) v0.10.0
- [flanneld](https://github.com/coreos/flannel) v0.12.0 - [kube-router](https://github.com/cloudnativelabs/kube-router) v0.2.1
- [kube-router](https://github.com/cloudnativelabs/kube-router) v0.4.0 - [multus](https://github.com/intel/multus-cni) v3.1.autoconf
- [multus](https://github.com/intel/multus-cni) v3.4.1 - [weave](https://github.com/weaveworks/weave) v2.5.0
- [weave](https://github.com/weaveworks/weave) v2.6.2 - Application
- Application - [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 - [cert-manager](https://github.com/jetstack/cert-manager) v0.5.2
- [rbd-provisioner](https://github.com/kubernetes-incubator/external-storage) v2.1.1-k8s1.11 - [coredns](https://github.com/coredns/coredns) v1.2.6
- [cert-manager](https://github.com/jetstack/cert-manager) v0.11.1 - [ingress-nginx](https://github.com/kubernetes/ingress-nginx) v0.21.0
- [coredns](https://github.com/coredns/coredns) v1.6.5
- [ingress-nginx](https://github.com/kubernetes/ingress-nginx) v0.30.0
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). Note: The list of validated [docker versions](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG-1.12.md) was updated to 1.11.1, 1.12.1, 1.13.1, 17.03, 17.06, 17.09, 18.06. 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 Note 2: rkt support as docker alternative is limited to control plane (etcd and
kubelet). Docker is still used for Kubernetes cluster workloads and network
plugins' related OS services. Also note, only one of the supported network
plugins can be deployed for a given single cluster.
- **Minimum required version of Kubernetes is v1.15** Requirements
- **Ansible v2.9+, Jinja 2.11+ 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](https://github.com/kubernetes-sigs/kubespray/blob/master/docs/downloads.md#offline-environment))
- The target servers are configured to allow **IPv4 forwarding**. - **Ansible v2.5 (or newer) and python-netaddr is installed on the machine
- **Your ssh key must be copied** to all the servers part of your inventory. that will run Ansible commands**
- The **firewalls are not managed**, you'll need to implement your own rules the way you used to. - **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**.
- **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.
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
should be configured in the target servers. Then the `ansible_become` flag should be configured in the target servers. Then the `ansible_become` flag
or command parameters `--become or -b` should be specified. or command parameters `--become or -b` should be specified.
Hardware: Network Plugins
These limits are safe guarded by Kubespray. Actual requirements for your workload can differ. For a sizing guide go to the [Building Large Clusters](https://kubernetes.io/docs/setup/cluster-large/#size-of-master-and-master-components) guide. ---------------
- Master You can choose between 6 network plugins. (default: `calico`, except Vagrant uses `flannel`)
- Memory: 1500 MB
- Node
- Memory: 1024 MB
## Network Plugins - [flannel](docs/flannel.md): gre/vxlan (layer 2) networking.
You can choose between 10 network plugins. (default: `calico`, except Vagrant uses `flannel`) - [calico](docs/calico.md): bgp (layer 3) networking.
- [flannel](docs/flannel.md): gre/vxlan (layer 2) networking. - [canal](https://github.com/projectcalico/canal): a composition of calico and flannel plugins.
- [Calico](https://docs.projectcalico.org/latest/introduction/) is a networking and network policy provider. Calico supports a flexible set of networking options - [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.
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. - [contiv](docs/contiv.md): supports vlan, vxlan, bgp and Cisco SDN networking. This plugin is able to
- [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.
- [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. 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](http://docs.weave.works/weave/latest_release/troubleshooting.html)).
- [kube-ovn](docs/kube-ovn.md): Kube-OVN integrates the OVN-based Network Virtualization with Kubernetes. It offers an advanced Container Network Fabric for Enterprises. - [kube-router](docs/kube-router.md): Kube-router is a L3 CNI for Kubernetes networking aiming to provide operational
- [kube-router](docs/kube-router.md): Kube-router is a L3 CNI for Kubernetes networking aiming to provide operational
simplicity and high performance: it uses IPVS to provide Kube Services Proxy (if setup to replace kube-proxy), simplicity and high performance: it uses IPVS to provide Kube Services Proxy (if setup to replace kube-proxy),
iptables for network policies, and BGP for ods L3 networking (with optionally BGP peering with out-of-cluster BGP peers). iptables for network policies, and BGP for ods L3 networking (with optionally BGP peering with out-of-cluster BGP peers).
It can also optionally advertise routes to Kubernetes cluster Pods CIDRs, ClusterIPs, ExternalIPs and LoadBalancerIPs. It can also optionally advertise routes to Kubernetes cluster Pods CIDRs, ClusterIPs, ExternalIPs and LoadBalancerIPs.
- [macvlan](docs/macvlan.md): Macvlan is a Linux network driver. Pods have their own unique Mac and Ip address, connected directly the physical (layer 2) network. - [multus](docs/multus.md): Multus is a meta CNI plugin that provides multiple network interface support to pods. For each interface Multus delegates CNI calls to secondary CNI plugins such as Calico, macvlan, etc.
- [multus](docs/multus.md): Multus is a meta CNI plugin that provides multiple network interface support to pods. For each interface Multus delegates CNI calls to secondary CNI plugins such as Calico, macvlan, etc.
The choice is defined with the variable `kube_network_plugin`. There is also an 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).
## 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/getting-started-guides/kubespray/](https://kubernetes.io/docs/getting-started-guides/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
--------------------------------------
- [Digital Rebar Provision](https://github.com/digitalrebar/provision/blob/v4/doc/integrations/ansible.rst) - [Digital Rebar Provision](https://github.com/digitalrebar/provision/blob/master/doc/integrations/ansible.rst)
- [Terraform Contrib](https://github.com/kubernetes-sigs/kubespray/tree/master/contrib/terraform) - [Fuel-ccp-installer](https://github.com/openstack/fuel-ccp-installer)
- [Terraform Contrib](https://github.com/kubernetes-sigs/kubespray/tree/master/contrib/terraform)
## CI Tests CI Tests
--------
[![Build graphs](https://gitlab.com/kargo-ci/kubernetes-sigs-kubespray/badges/master/build.svg)](https://gitlab.com/kargo-ci/kubernetes-sigs-kubespray/pipelines) [![Build graphs](https://gitlab.com/kubespray-ci/kubernetes-incubator__kubespray/badges/master/build.svg)](https://gitlab.com/kubespray-ci/kubernetes-incubator__kubespray/pipelines)
CI/end-to-end tests sponsored by Google (GCE) 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

@@ -3,46 +3,38 @@
The Kubespray Project is released on an as-needed basis. The process is as follows: The Kubespray Project is released on an as-needed basis. The process is as follows:
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 [OWNERS](OWNERS) must LGTM this release
3. The `kube_version_min_required` variable is set to `n-1` 3. An OWNER runs `git tag -s $VERSION` and inserts the changelog and pushes the tag with `git push $VERSION`
4. Remove hashes for [EOL versions](https://github.com/kubernetes/sig-release/blob/master/releases/patch-releases.md) of kubernetes from `*_checksums` variables. 4. The release issue is closed
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. An announcement email is sent to `kubernetes-dev@googlegroups.com` with the subject `[ANNOUNCE] Kubespray $VERSION is released`
6. An approver creates a release branch in the form `release-X.Y`
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
8. The `KUBESPRAY_VERSION` variable is updated in `.gitlab-ci.yml`
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 does not maintain stable branches for releases. Releases are tags, not
branches, and there are no backports. Therefore, there is no need for merge
freezes as well.
* Security patches and bugs might be backported. * Fixes for major releases (vX.x.0) and minor releases (vX.Y.x) are delivered
* Fixes for major releases (vX.Y) and minor releases (vX.Y.Z) 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

111
Vagrantfile vendored
View File

@@ -7,72 +7,58 @@ 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")
COREOS_URL_TEMPLATE = "https://storage.googleapis.com/%s.release.core-os.net/amd64-usr/current/coreos_production_vagrant.json" COREOS_URL_TEMPLATE = "https://storage.googleapis.com/%s.release.core-os.net/amd64-usr/current/coreos_production_vagrant.json"
FLATCAR_URL_TEMPLATE = "https://%s.release.flatcar-linux.net/amd64-usr/current/flatcar_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 = {
"coreos-stable" => {box: "coreos-stable", user: "core", box_url: COREOS_URL_TEMPLATE % ["stable"]}, "coreos-stable" => {box: "coreos-stable", user: "core", box_url: COREOS_URL_TEMPLATE % ["stable"]},
"coreos-alpha" => {box: "coreos-alpha", user: "core", box_url: COREOS_URL_TEMPLATE % ["alpha"]}, "coreos-alpha" => {box: "coreos-alpha", user: "core", box_url: COREOS_URL_TEMPLATE % ["alpha"]},
"coreos-beta" => {box: "coreos-beta", user: "core", box_url: COREOS_URL_TEMPLATE % ["beta"]}, "coreos-beta" => {box: "coreos-beta", user: "core", box_url: COREOS_URL_TEMPLATE % ["beta"]},
"flatcar-stable" => {box: "flatcar-stable", user: "core", box_url: FLATCAR_URL_TEMPLATE % ["stable"]}, "ubuntu1604" => {box: "generic/ubuntu1604", user: "vagrant"},
"flatcar-beta" => {box: "flatcar-beta", user: "core", box_url: FLATCAR_URL_TEMPLATE % ["beta"]}, "ubuntu1804" => {box: "generic/ubuntu1804", user: "vagrant"},
"flatcar-alpha" => {box: "flatcar-alpha", user: "core", box_url: FLATCAR_URL_TEMPLATE % ["alpha"]}, "centos" => {box: "centos/7", user: "vagrant"},
"flatcar-edge" => {box: "flatcar-edge", user: "core", box_url: FLATCAR_URL_TEMPLATE % ["edge"]}, "centos-bento" => {box: "bento/centos-7.5", user: "vagrant"},
"ubuntu1604" => {box: "generic/ubuntu1604", user: "vagrant"}, "fedora" => {box: "fedora/28-cloud-base", user: "vagrant"},
"ubuntu1804" => {box: "generic/ubuntu1804", user: "vagrant"}, "opensuse" => {box: "opensuse/openSUSE-42.3-x86_64", user: "vagrant"},
"ubuntu2004" => {box: "geerlingguy/ubuntu2004", user: "vagrant"}, "opensuse-tumbleweed" => {box: "opensuse/openSUSE-Tumbleweed-x86_64", user: "vagrant"},
"centos" => {box: "centos/7", user: "vagrant"},
"centos-bento" => {box: "bento/centos-7.6", user: "vagrant"},
"centos8" => {box: "centos/8", user: "vagrant"},
"centos8-bento" => {box: "bento/centos-8", user: "vagrant"},
"fedora30" => {box: "fedora/30-cloud-base", user: "vagrant"},
"fedora31" => {box: "fedora/31-cloud-base", user: "vagrant"},
"opensuse" => {box: "bento/opensuse-leap-15.1", user: "vagrant"},
"opensuse-tumbleweed" => {box: "opensuse/Tumbleweed.x86_64", user: "vagrant"},
"oraclelinux" => {box: "generic/oracle7", user: "vagrant"},
} }
if File.exist?(CONFIG)
require CONFIG
end
# Defaults for config options defined in CONFIG # Defaults for config options defined in CONFIG
$num_instances ||= 3 $num_instances = 3
$instance_name_prefix ||= "k8s" $instance_name_prefix = "k8s"
$vm_gui ||= false $vm_gui = false
$vm_memory ||= 2048 $vm_memory = 2048
$vm_cpus ||= 1 $vm_cpus = 1
$shared_folders ||= {} $shared_folders = {}
$forwarded_ports ||= {} $forwarded_ports = {}
$subnet ||= "172.18.8" $subnet = "172.17.8"
$os ||= "ubuntu1804" $os = "ubuntu1804"
$network_plugin ||= "flannel" $network_plugin = "flannel"
# Setting multi_networking to true will install Multus: https://github.com/intel/multus-cni # Setting multi_networking to true will install Multus: https://github.com/intel/multus-cni
$multi_networking ||= false $multi_networking = false
# The first three nodes are etcd servers # The first three nodes are etcd servers
$etcd_instances ||= $num_instances $etcd_instances = $num_instances
# The first two nodes are kube masters # The first two nodes are kube masters
$kube_master_instances ||= $num_instances == 1 ? $num_instances : ($num_instances - 1) $kube_master_instances = $num_instances == 1 ? $num_instances : ($num_instances - 1)
# All nodes are kube nodes # All nodes are kube nodes
$kube_node_instances ||= $num_instances $kube_node_instances = $num_instances
# The following only works when using the libvirt provider # The following only works when using the libvirt provider
$kube_node_instances_with_disks ||= false $kube_node_instances_with_disks = false
$kube_node_instances_with_disks_size ||= "20G" $kube_node_instances_with_disks_size = "20G"
$kube_node_instances_with_disks_number ||= 2 $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" $playbook = "cluster.yml"
host_vars = {} host_vars = {}
if File.exist?(CONFIG)
require CONFIG
end
$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
@@ -111,13 +97,6 @@ Vagrant.configure("2") do |config|
# always use Vagrants insecure key # always use Vagrants insecure key
config.ssh.insert_key = false config.ssh.insert_key = false
if ($override_disk_size)
unless Vagrant.has_plugin?("vagrant-disksize")
system "vagrant plugin install vagrant-disksize"
end
config.disksize.size = $disk_size
end
(1..$num_instances).each do |i| (1..$num_instances).each do |i|
config.vm.define vm_name = "%s-%01d" % [$instance_name_prefix, i] do |node| config.vm.define vm_name = "%s-%01d" % [$instance_name_prefix, i] do |node|
@@ -141,7 +120,6 @@ Vagrant.configure("2") do |config|
vb.cpus = $vm_cpus vb.cpus = $vm_cpus
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
end end
node.vm.provider :libvirt do |lv| node.vm.provider :libvirt do |lv|
@@ -187,37 +165,24 @@ Vagrant.configure("2") do |config|
host_vars[vm_name] = { host_vars[vm_name] = {
"ip": ip, "ip": ip,
"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": "True",
"download_localhost": "False",
"download_cache_dir": ENV['HOME'] + "/kubespray_cache",
# Make kubespray cache even when download_run_once is false
"download_force_cache": "True",
# Keeping the cache on the nodes can improve provisioning speed while debugging kubespray
"download_keep_remote_cache": "False",
"docker_keepcache": "1", "docker_keepcache": "1",
# These two settings will put kubectl and admin.config in $inventory/artifacts "download_run_once": "True",
"kubeconfig_localhost": "True", "download_localhost": "False"
"kubectl_localhost": "True",
"local_path_provisioner_enabled": "#{$local_path_provisioner_enabled}",
"local_path_provisioner_claim_root": "#{$local_path_provisioner_claim_root}",
"ansible_ssh_user": SUPPORTED_OS[$os][:user]
} }
# Only execute the Ansible provisioner once, when all the machines are up and ready. # Only execute the Ansible provisioner once, when all the machines are up and ready.
if i == $num_instances if i == $num_instances
node.vm.provision "ansible" do |ansible| node.vm.provision "ansible" do |ansible|
ansible.playbook = $playbook ansible.playbook = $playbook
$ansible_inventory_path = File.join( $inventory, "hosts.ini") if File.exist?(File.join( $inventory, "hosts.ini"))
if File.exist?($ansible_inventory_path) ansible.inventory_path = $inventory
ansible.inventory_path = $ansible_inventory_path
end end
ansible.become = true ansible.become = true
ansible.limit = "all,localhost" ansible.limit = "all"
ansible.host_key_checking = false ansible.host_key_checking = false
ansible.raw_arguments = ["--forks=#{$num_instances}", "--flush-cache", "-e ansible_become_pass=vagrant"] ansible.raw_arguments = ["--forks=#{$num_instances}", "--flush-cache", "--ask-become-pass"]
ansible.host_vars = host_vars ansible.host_vars = host_vars
#ansible.tags = ['download'] #ansible.tags = ['download']
ansible.groups = { ansible.groups = {

View File

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

View File

@@ -4,20 +4,16 @@ ssh_args = -o ControlMaster=auto -o ControlPersist=30m -o ConnectionAttempts=100
#control_path = ~/.ssh/ansible-%%r@%%h:%%p #control_path = ~/.ssh/ansible-%%r@%%h:%%p
[defaults] [defaults]
strategy_plugins = plugins/mitogen/ansible_mitogen/plugins/strategy strategy_plugins = plugins/mitogen/ansible_mitogen/plugins/strategy
# https://github.com/ansible/ansible/issues/56930 (to ignore group names with - and .)
force_valid_group_names = ignore
host_key_checking=False 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
deprecation_warnings=False deprecation_warnings=False
inventory_ignore_extensions = ~, .orig, .bak, .ini, .cfg, .retry, .pyc, .pyo, .creds, .gpg inventory_ignore_extensions = ~, .orig, .bak, .ini, .cfg, .retry, .pyc, .pyo, .creds
[inventory] [inventory]
ignore_patterns = artifacts, credentials ignore_patterns = artifacts, credentials

View File

@@ -1,15 +0,0 @@
---
- hosts: localhost
gather_facts: false
become: no
vars:
minimal_ansible_version: 2.8.0
ansible_connection: local
tasks:
- name: "Check ansible version >={{ minimal_ansible_version }}"
assert:
msg: "Ansible must be {{ minimal_ansible_version }} or higher"
that:
- ansible_version.string is version(minimal_ansible_version, ">=")
tags:
- check

View File

@@ -1,135 +1,136 @@
--- ---
- name: Check ansible version - hosts: localhost
import_playbook: ansible_version.yml
- hosts: all
gather_facts: false gather_facts: false
tasks: tasks:
- name: "Set up proxy environment" - name: "Check ansible version !=2.7.0"
set_fact: assert:
proxy_env: msg: "Ansible V2.7.0 can't be used until: https://github.com/ansible/ansible/issues/46600 is fixed"
http_proxy: "{{ http_proxy | default ('') }}" that:
HTTP_PROXY: "{{ http_proxy | default ('') }}" - ansible_version.string is version("2.7.0", "!=")
https_proxy: "{{ https_proxy | default ('') }}" - ansible_version.string is version("2.5.0", ">=")
HTTPS_PROXY: "{{ https_proxy | default ('') }}" tags:
no_proxy: "{{ no_proxy | default ('') }}" - check
NO_PROXY: "{{ no_proxy | default ('') }}" vars:
no_log: true ansible_connection: local
- hosts: localhost
gather_facts: false
tasks:
- name: deploy warning for non kubeadm
debug:
msg: "DEPRECATION: non-kubeadm deployment is deprecated from v2.9. Will be removed in next release."
when: not kubeadm_enabled and not skip_non_kubeadm_warning
- name: deploy cluster for non kubeadm
pause:
prompt: "Are you sure you want to deploy cluster using the deprecated non-kubeadm mode."
echo: no
when: not kubeadm_enabled and not skip_non_kubeadm_warning
- hosts: bastion[0] - hosts: bastion[0]
gather_facts: False gather_facts: False
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:calico-rr
strategy: linear
any_errors_fatal: "{{ any_errors_fatal | default(true) }}" any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
gather_facts: false gather_facts: false
vars:
# Need to disable pipelining for bootstrap-os as some systems have requiretty in sudoers set, which makes pipelining
# fail. bootstrap-os fixes this on these systems, so in later plays it can be enabled.
ansible_ssh_pipelining: false
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- { role: bootstrap-os, tags: bootstrap-os} - { role: bootstrap-os, tags: bootstrap-os}
- name: Gather facts - hosts: k8s-cluster:etcd:calico-rr
import_playbook: facts.yml any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
vars:
ansible_ssh_pipelining: true
gather_facts: true
pre_tasks:
- name: gather facts from all instances
setup:
delegate_to: "{{item}}"
delegate_facts: True
with_items: "{{ groups['k8s-cluster'] + groups['etcd'] + groups['calico-rr']|default([]) }}"
- hosts: k8s-cluster:etcd - hosts: k8s-cluster:etcd:calico-rr
gather_facts: False
any_errors_fatal: "{{ any_errors_fatal | default(true) }}" any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
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 }}" 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) }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- role: etcd - { role: etcd, tags: etcd, etcd_cluster_setup: true, etcd_events_cluster_setup: "{{ etcd_events_cluster_enabled }}" }
tags: etcd
vars: - hosts: k8s-cluster:calico-rr
etcd_cluster_setup: true any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
etcd_events_cluster_setup: "{{ etcd_events_cluster_enabled }}" roles:
when: not etcd_kubeadm_enabled| default(false) - { role: kubespray-defaults}
- { role: etcd, tags: etcd, etcd_cluster_setup: false, etcd_events_cluster_setup: 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) }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- role: etcd
tags: etcd
vars:
etcd_cluster_setup: false
etcd_events_cluster_setup: false
when: not etcd_kubeadm_enabled| default(false)
- hosts: k8s-cluster
gather_facts: False
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
roles:
- { role: kubespray-defaults }
- { role: kubernetes/node, tags: node } - { role: kubernetes/node, tags: node }
environment: "{{ proxy_env }}" 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) }}"
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) }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- { role: kubernetes/kubeadm, tags: kubeadm} - { role: kubernetes/kubeadm, tags: kubeadm, when: "kubeadm_enabled" }
- { role: network_plugin, tags: network } - { role: network_plugin, tags: network }
- { role: kubernetes/node-label, tags: node-label }
- hosts: calico-rr
gather_facts: False
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
roles:
- { role: kubespray-defaults }
- { 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) }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- { role: kubernetes-apps/rotate_tokens, tags: rotate_tokens, when: "secret_changed|default(false)" } - { role: kubernetes-apps/rotate_tokens, tags: rotate_tokens, when: "secret_changed|default(false)" }
- { role: win_nodes/kubernetes_patch, tags: ["master", "win_nodes"] } - { role: win_nodes/kubernetes_patch, tags: ["master", "win_nodes"], when: "kubeadm_enabled" }
- 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) }}"
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: calico-rr
gather_facts: False
any_errors_fatal: "{{ any_errors_fatal | default(true) }}" any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- { role: kubernetes-apps, tags: apps } - { role: network_plugin/calico/rr, tags: network }
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) }}"
roles: roles:
- { role: kubespray-defaults } - { role: kubespray-defaults}
- { role: dnsmasq, when: "dns_mode == 'dnsmasq_kubedns'", tags: dnsmasq }
- { 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 }
environment: "{{proxy_env}}"
- hosts: kube-master
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
roles:
- { role: kubespray-defaults}
- { role: kubernetes-apps, tags: apps }

View File

@@ -42,11 +42,8 @@ class SearchEC2Tags(object):
region = os.environ['REGION'] region = os.environ['REGION']
ec2 = boto3.resource('ec2', region) ec2 = boto3.resource('ec2', region)
filters = [{'Name': 'tag:'+tag_key, 'Values': tag_value}, {'Name': 'instance-state-name', 'Values': ['running']}]
cluster_name = os.getenv('CLUSTER_NAME') instances = ec2.instances.filter(Filters=[{'Name': 'tag:'+tag_key, 'Values': tag_value}, {'Name': 'instance-state-name', 'Values': ['running']}])
if cluster_name:
filters.append({'Name': 'tag-key', 'Values': ['kubernetes.io/cluster/'+cluster_name]})
instances = ec2.instances.filter(Filters=filters)
for instance in instances: for instance in instances:
##Suppose default vpc_visibility is private ##Suppose default vpc_visibility is private

View File

@@ -15,9 +15,8 @@ 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
@@ -60,6 +59,6 @@ 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
$ ansible-playbook -i contrib/azurerm/inventory -u devops --become -e "@inventory/sample/group_vars/all/all.yml" cluster.yml $ ansible-playbook -i contrib/azurerm/inventory -u devops --become -e "@inventory/sample/group_vars/all.yml" cluster.yml
``` ```

View File

@@ -11,9 +11,9 @@ fi
ansible-playbook generate-templates.yml ansible-playbook generate-templates.yml
az deployment group create --template-file ./.generated/network.json -g $AZURE_RESOURCE_GROUP az group deployment create --template-file ./.generated/network.json -g $AZURE_RESOURCE_GROUP
az deployment group create --template-file ./.generated/storage.json -g $AZURE_RESOURCE_GROUP az group deployment create --template-file ./.generated/storage.json -g $AZURE_RESOURCE_GROUP
az deployment group create --template-file ./.generated/availability-sets.json -g $AZURE_RESOURCE_GROUP az group deployment create --template-file ./.generated/availability-sets.json -g $AZURE_RESOURCE_GROUP
az deployment group create --template-file ./.generated/bastion.json -g $AZURE_RESOURCE_GROUP az group deployment create --template-file ./.generated/bastion.json -g $AZURE_RESOURCE_GROUP
az deployment group create --template-file ./.generated/masters.json -g $AZURE_RESOURCE_GROUP az group deployment create --template-file ./.generated/masters.json -g $AZURE_RESOURCE_GROUP
az deployment group create --template-file ./.generated/minions.json -g $AZURE_RESOURCE_GROUP az group deployment create --template-file ./.generated/minions.json -g $AZURE_RESOURCE_GROUP

View File

@@ -7,7 +7,7 @@ cluster_name: example
# node that can be used to access the masters and minions # node that can be used to access the masters and minions
use_bastion: false use_bastion: false
# Set this to a preferred name that will be used as the first part of the dns name for your bastotion host. For example: k8s-bastion.<azureregion>.cloudapp.azure.com. # Set this to a prefered name that will be used as the first part of the dns name for your bastotion host. For example: k8s-bastion.<azureregion>.cloudapp.azure.com.
# This is convenient when exceptions have to be configured on a firewall to allow ssh to the given bastion host. # This is convenient when exceptions have to be configured on a firewall to allow ssh to the given bastion host.
# bastion_domain_prefix: k8s-bastion # bastion_domain_prefix: k8s-bastion

View File

@@ -4,11 +4,8 @@
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
- name: Set vm_list - set_fact:
set_fact:
vm_list: "{{ vm_list_cmd.stdout }}" vm_list: "{{ vm_list_cmd.stdout }}"
- name: Generate inventory - name: Generate inventory
template: template: src=inventory.j2 dest="{{playbook_dir}}/inventory"
src: inventory.j2
dest: "{{ playbook_dir }}/inventory"

View File

@@ -8,22 +8,9 @@
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 - set_fact:
command: az network public-ip show -o json -g {{ azure_resource_group }} -n kubernetes-api-pubip
register: lb_pubip_cmd
- name: Set VM IP, roles lists and load balancer public IP
set_fact:
vm_ip_list: "{{ vm_ip_list_cmd.stdout }}" vm_ip_list: "{{ vm_ip_list_cmd.stdout }}"
vm_roles_list: "{{ vm_list_cmd.stdout }}" vm_roles_list: "{{ vm_list_cmd.stdout }}"
lb_pubip: "{{ lb_pubip_cmd.stdout }}"
- name: Generate inventory - name: Generate inventory
template: template: src=inventory.j2 dest="{{playbook_dir}}/inventory"
src: inventory.j2
dest: "{{ playbook_dir }}/inventory"
- name: Generate Load Balancer variables
template:
src: loadbalancer_vars.j2
dest: "{{ playbook_dir }}/loadbalancer_vars.yml"

View File

@@ -1,8 +0,0 @@
## External LB example config
apiserver_loadbalancer_domain_name: {{ lb_pubip.dnsSettings.fqdn }}
loadbalancer_apiserver:
address: {{ lb_pubip.ipAddress }}
port: 6443
## Internal loadbalancers for apiservers
loadbalancer_apiserver_localhost: false

View File

@@ -1,4 +1,3 @@
---
apiVersion: "2015-06-15" apiVersion: "2015-06-15"
virtualNetworkName: "{{ azure_virtual_network_name | default('KubeVNET') }}" virtualNetworkName: "{{ azure_virtual_network_name | default('KubeVNET') }}"
@@ -29,9 +28,10 @@ sshKeyPath: "/home/{{admin_username}}/.ssh/authorized_keys"
imageReference: imageReference:
publisher: "OpenLogic" publisher: "OpenLogic"
offer: "CentOS" offer: "CentOS"
sku: "7.5" sku: "7.2"
version: "latest" version: "latest"
imageReferenceJson: "{{imageReference|to_json}}" imageReferenceJson: "{{imageReference|to_json}}"
storageAccountName: "sa{{nameSuffix | replace('-', '')}}" storageAccountName: "sa{{nameSuffix | replace('-', '')}}"
storageAccountType: "{{ azure_storage_account_type | default('Standard_LRS') }}" storageAccountType: "{{ azure_storage_account_type | default('Standard_LRS') }}"

View File

@@ -1,18 +1,9 @@
--- - set_fact:
- name: Set base_dir base_dir: "{{playbook_dir}}/.generated/"
set_fact:
base_dir: "{{ playbook_dir }}/.generated/"
- name: Create base_dir - file: path={{base_dir}} state=directory recurse=true
file:
path: "{{ base_dir }}"
state: directory
recurse: true
- name: Store json files in base_dir - template: src={{item}} dest="{{base_dir}}/{{item}}"
template:
src: "{{ item }}"
dest: "{{ base_dir }}/{{ item }}"
with_items: with_items:
- network.json - network.json
- storage.json - storage.json

View File

@@ -1,3 +1,2 @@
---
# See distro.yaml for supported node_distro images # See distro.yaml for supported node_distro images
node_distro: debian node_distro: debian

View File

@@ -1,4 +1,3 @@
---
distro_settings: distro_settings:
debian: &DEBIAN debian: &DEBIAN
image: "debian:9.5" image: "debian:9.5"

View File

@@ -1,7 +1,7 @@
---
# kubespray-dind.yaml: minimal kubespray ansible playbook usable for DIND # kubespray-dind.yaml: minimal kubespray ansible playbook usable for DIND
# See contrib/dind/README.md # See contrib/dind/README.md
kube_api_anonymous_auth: true kube_api_anonymous_auth: true
kubeadm_enabled: true
kubelet_fail_swap_on: false kubelet_fail_swap_on: false

View File

@@ -1,4 +1,3 @@
---
- name: set_fact distro_setup - name: set_fact distro_setup
set_fact: set_fact:
distro_setup: "{{ distro_settings[node_distro] }}" distro_setup: "{{ distro_settings[node_distro] }}"
@@ -12,7 +11,7 @@
- name: Null-ify some linux tools to ease DIND - name: Null-ify some linux tools to ease DIND
file: file:
src: "/bin/true" src: "/bin/true"
dest: "{{ item }}" dest: "{{item}}"
state: link state: link
force: yes force: yes
with_items: with_items:
@@ -34,7 +33,7 @@
# Delete docs # Delete docs
path-exclude=/usr/share/doc/* path-exclude=/usr/share/doc/*
path-include=/usr/share/doc/*/copyright path-include=/usr/share/doc/*/copyright
dest: /etc/dpkg/dpkg.cfg.d/01_nodoc dest: /etc/dpkg/dpkg.cfg.d/01_nodoc
when: when:
- ansible_os_family == 'Debian' - ansible_os_family == 'Debian'
@@ -52,11 +51,11 @@
- rsyslog - rsyslog
- "{{ distro_ssh_service }}" - "{{ distro_ssh_service }}"
- name: Create distro user "{{ distro_user }}" - name: Create distro user "{{distro_user}}"
user: user:
name: "{{ distro_user }}" name: "{{ distro_user }}"
uid: 1000 uid: 1000
# groups: sudo #groups: sudo
append: yes append: yes
- name: Allow password-less sudo to "{{ distro_user }}" - name: Allow password-less sudo to "{{ distro_user }}"

View File

@@ -1,4 +1,3 @@
---
- name: set_fact distro_setup - name: set_fact distro_setup
set_fact: set_fact:
distro_setup: "{{ distro_settings[node_distro] }}" distro_setup: "{{ distro_settings[node_distro] }}"
@@ -19,7 +18,7 @@
state: started state: started
hostname: "{{ item }}" hostname: "{{ item }}"
command: "{{ distro_init }}" command: "{{ distro_init }}"
# recreate: yes #recreate: yes
privileged: true privileged: true
tmpfs: tmpfs:
- /sys/module/nf_conntrack/parameters - /sys/module/nf_conntrack/parameters
@@ -28,7 +27,7 @@
- /lib/modules:/lib/modules - /lib/modules:/lib/modules
- "{{ item }}:/dind/docker" - "{{ item }}:/dind/docker"
register: containers register: containers
with_items: "{{ groups.containers }}" with_items: "{{groups.containers}}"
tags: tags:
- addresses - addresses
@@ -79,7 +78,6 @@
with_items: "{{ containers.results }}" with_items: "{{ containers.results }}"
- name: Early hack image install to adapt for DIND - name: Early hack image install to adapt for DIND
# noqa 302 - this task uses the raw module intentionally
raw: | raw: |
rm -fv /usr/bin/udevadm /usr/sbin/udevadm rm -fv /usr/bin/udevadm /usr/sbin/udevadm
delegate_to: "{{ item._ansible_item_label|default(item.item) }}" delegate_to: "{{ item._ansible_item_label|default(item.item) }}"

View File

@@ -1,6 +1,8 @@
DISTROS=(debian centos) DISTROS=(debian centos)
NETCHECKER_HOST=${NODES[0]} NETCHECKER_HOST=${NODES[0]}
EXTRAS=( EXTRAS=(
'kube_network_plugin=kube-router {"kube_router_run_service_proxy":false}' 'kube_network_plugin=kube-router {"kubeadm_enabled":true,"kube_router_run_service_proxy":false}'
'kube_network_plugin=kube-router {"kube_router_run_service_proxy":true}' 'kube_network_plugin=kube-router {"kubeadm_enabled":true,"kube_router_run_service_proxy":true}'
'kube_network_plugin=kube-router {"kubeadm_enabled":false,"kube_router_run_service_proxy":false}'
'kube_network_plugin=kube-router {"kubeadm_enabled":false,"kube_router_run_service_proxy":true}'
) )

View File

@@ -1,8 +1,8 @@
DISTROS=(debian centos) DISTROS=(debian centos)
EXTRAS=( EXTRAS=(
'kube_network_plugin=calico {}' 'kube_network_plugin=calico {"kubeadm_enabled":true}'
'kube_network_plugin=canal {}' 'kube_network_plugin=canal {"kubeadm_enabled":true}'
'kube_network_plugin=cilium {}' 'kube_network_plugin=cilium {"kubeadm_enabled":true}'
'kube_network_plugin=flannel {}' 'kube_network_plugin=flannel {"kubeadm_enabled":true}'
'kube_network_plugin=weave {}' 'kube_network_plugin=weave {"kubeadm_enabled":true}'
) )

View File

@@ -17,11 +17,6 @@
# #
# Advanced usage: # Advanced usage:
# Add another host after initial creation: inventory.py 10.10.1.5 # Add another host after initial creation: inventory.py 10.10.1.5
# Add range of hosts: inventory.py 10.10.1.3-10.10.1.5
# Add hosts with different ip and access ip:
# inventory.py 10.0.0.1,192.168.10.1 10.0.0.2,192.168.10.2 10.0.0.3,192.168.1.3
# Add hosts with a specific hostname, ip, and optional access ip:
# inventory.py first,10.0.0.1,192.168.10.1 second,10.0.0.2 last,10.0.0.3
# Delete a host: inventory.py -10.10.1.3 # Delete a host: inventory.py -10.10.1.3
# Delete a host by id: inventory.py -node1 # Delete a host by id: inventory.py -node1
# #
@@ -36,22 +31,21 @@
# ip: X.X.X.X # ip: X.X.X.X
from collections import OrderedDict from collections import OrderedDict
from ipaddress import ip_address try:
from ruamel.yaml import YAML import configparser
except ImportError:
import ConfigParser as configparser
import os import os
import re import re
import sys import sys
ROLES = ['all', 'kube-master', 'kube-node', 'etcd', 'k8s-cluster', ROLES = ['all', 'kube-master', 'kube-node', 'etcd', 'k8s-cluster:children',
'calico-rr'] 'calico-rr', 'vault']
PROTECTED_NAMES = ROLES PROTECTED_NAMES = ROLES
AVAILABLE_COMMANDS = ['help', 'print_cfg', 'print_ips', 'print_hostnames', AVAILABLE_COMMANDS = ['help', 'print_cfg', 'print_ips', 'load']
'load']
_boolean_states = {'1': True, 'yes': True, 'true': True, 'on': True, _boolean_states = {'1': True, 'yes': True, 'true': True, 'on': True,
'0': False, 'no': False, 'false': False, 'off': False} '0': False, 'no': False, 'false': False, 'off': False}
yaml = YAML()
yaml.Representer.add_representer(OrderedDict, yaml.Representer.represent_dict)
def get_var_as_bool(name, default): def get_var_as_bool(name, default):
@@ -60,9 +54,7 @@ def get_var_as_bool(name, default):
# Configurable as shell vars start # Configurable as shell vars start
CONFIG_FILE = os.environ.get("CONFIG_FILE", "./inventory/sample/hosts.ini")
CONFIG_FILE = os.environ.get("CONFIG_FILE", "./inventory/sample/hosts.yaml")
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("SCALE_THRESHOLD", 200)) MASSIVE_SCALE_THRESHOLD = int(os.environ.get("SCALE_THRESHOLD", 200))
@@ -76,14 +68,11 @@ HOST_PREFIX = os.environ.get("HOST_PREFIX", "node")
class KubesprayInventory(object): class KubesprayInventory(object):
def __init__(self, changed_hosts=None, config_file=None): def __init__(self, changed_hosts=None, config_file=None):
self.config = configparser.ConfigParser(allow_no_value=True,
delimiters=('\t', ' '))
self.config_file = config_file self.config_file = config_file
self.yaml_config = {}
if self.config_file: if self.config_file:
try: self.config.read(self.config_file)
self.hosts_file = open(config_file, 'r')
self.yaml_config = yaml.load_all(self.hosts_file)
except OSError:
pass
if changed_hosts and changed_hosts[0] in AVAILABLE_COMMANDS: if changed_hosts and changed_hosts[0] in AVAILABLE_COMMANDS:
self.parse_command(changed_hosts[0], changed_hosts[1:]) self.parse_command(changed_hosts[0], changed_hosts[1:])
@@ -92,21 +81,18 @@ class KubesprayInventory(object):
self.ensure_required_groups(ROLES) self.ensure_required_groups(ROLES)
if changed_hosts: if changed_hosts:
changed_hosts = self.range2ips(changed_hosts)
self.hosts = self.build_hostnames(changed_hosts) self.hosts = self.build_hostnames(changed_hosts)
self.purge_invalid_hosts(self.hosts.keys(), PROTECTED_NAMES) self.purge_invalid_hosts(self.hosts.keys(), PROTECTED_NAMES)
self.set_all(self.hosts) self.set_all(self.hosts)
self.set_k8s_cluster() self.set_k8s_cluster()
etcd_hosts_count = 3 if len(self.hosts.keys()) >= 3 else 1 self.set_etcd(list(self.hosts.keys())[:3])
self.set_etcd(list(self.hosts.keys())[:etcd_hosts_count])
if len(self.hosts) >= SCALE_THRESHOLD: if len(self.hosts) >= SCALE_THRESHOLD:
self.set_kube_master(list(self.hosts.keys())[ self.set_kube_master(list(self.hosts.keys())[3:5])
etcd_hosts_count:(etcd_hosts_count + KUBE_MASTERS)])
else: else:
self.set_kube_master(list(self.hosts.keys())[:KUBE_MASTERS]) self.set_kube_master(list(self.hosts.keys())[:2])
self.set_kube_node(self.hosts.keys()) self.set_kube_node(self.hosts.keys())
if len(self.hosts) >= SCALE_THRESHOLD: if len(self.hosts) >= SCALE_THRESHOLD:
self.set_calico_rr(list(self.hosts.keys())[:etcd_hosts_count]) self.set_calico_rr(list(self.hosts.keys())[:3])
else: # Show help if no options else: # Show help if no options
self.show_help() self.show_help()
sys.exit(0) sys.exit(0)
@@ -115,9 +101,8 @@ class KubesprayInventory(object):
def write_config(self, config_file): def write_config(self, config_file):
if config_file: if config_file:
with open(self.config_file, 'w') as f: with open(config_file, 'w') as f:
yaml.dump(self.yaml_config, f) self.config.write(f)
else: else:
print("WARNING: Unable to save config. Make sure you set " print("WARNING: Unable to save config. Make sure you set "
"CONFIG_FILE env var.") "CONFIG_FILE env var.")
@@ -127,29 +112,28 @@ class KubesprayInventory(object):
print("DEBUG: {0}".format(msg)) print("DEBUG: {0}".format(msg))
def get_ip_from_opts(self, optstring): def get_ip_from_opts(self, optstring):
if 'ip' in optstring: opts = optstring.split(' ')
return optstring['ip'] for opt in opts:
else: if '=' not in opt:
raise ValueError("IP parameter not found in options") continue
k, v = opt.split('=')
if k == "ip":
return v
raise ValueError("IP parameter not found in options")
def ensure_required_groups(self, groups): def ensure_required_groups(self, groups):
for group in groups: for group in groups:
if group == 'all': try:
self.debug("Adding group {0}".format(group)) self.debug("Adding group {0}".format(group))
if group not in self.yaml_config: self.config.add_section(group)
all_dict = OrderedDict([('hosts', OrderedDict({})), except configparser.DuplicateSectionError:
('children', OrderedDict({}))]) pass
self.yaml_config = {'all': all_dict}
else:
self.debug("Adding group {0}".format(group))
if group not in self.yaml_config['all']['children']:
self.yaml_config['all']['children'][group] = {'hosts': {}}
def get_host_id(self, host): def get_host_id(self, host):
'''Returns integer host ID (without padding) from a given hostname.''' '''Returns integer host ID (without padding) from a given hostname.'''
try: try:
short_hostname = host.split('.')[0] short_hostname = host.split('.')[0]
return int(re.findall("\\d+$", short_hostname)[-1]) return int(re.findall("\d+$", short_hostname)[-1])
except IndexError: except IndexError:
raise ValueError("Host name must end in an integer") raise ValueError("Host name must end in an integer")
@@ -157,12 +141,12 @@ class KubesprayInventory(object):
existing_hosts = OrderedDict() existing_hosts = OrderedDict()
highest_host_id = 0 highest_host_id = 0
try: try:
for host in self.yaml_config['all']['hosts']: for host, opts in self.config.items('all'):
existing_hosts[host] = self.yaml_config['all']['hosts'][host] existing_hosts[host] = opts
host_id = self.get_host_id(host) host_id = self.get_host_id(host)
if host_id > highest_host_id: if host_id > highest_host_id:
highest_host_id = host_id highest_host_id = host_id
except Exception: except configparser.NoSectionError:
pass pass
# FIXME(mattymo): Fix condition where delete then add reuses highest id # FIXME(mattymo): Fix condition where delete then add reuses highest id
@@ -179,66 +163,22 @@ class KubesprayInventory(object):
self.debug("Marked {0} for deletion.".format(realhost)) self.debug("Marked {0} for deletion.".format(realhost))
self.delete_host_by_ip(all_hosts, realhost) self.delete_host_by_ip(all_hosts, realhost)
elif host[0].isdigit(): elif host[0].isdigit():
if ',' in host:
ip, access_ip = host.split(',')
else:
ip = host
access_ip = host
if self.exists_hostname(all_hosts, host): if self.exists_hostname(all_hosts, host):
self.debug("Skipping existing host {0}.".format(host)) self.debug("Skipping existing host {0}.".format(host))
continue continue
elif self.exists_ip(all_hosts, ip): elif self.exists_ip(all_hosts, host):
self.debug("Skipping existing host {0}.".format(ip)) self.debug("Skipping existing host {0}.".format(host))
continue continue
next_host = "{0}{1}".format(HOST_PREFIX, next_host_id) next_host = "{0}{1}".format(HOST_PREFIX, next_host_id)
next_host_id += 1 next_host_id += 1
all_hosts[next_host] = {'ansible_host': access_ip, all_hosts[next_host] = "ansible_host={0} ip={1}".format(
'ip': ip, host, host)
'access_ip': access_ip}
elif host[0].isalpha(): elif host[0].isalpha():
if ',' in host: raise Exception("Adding hosts by hostname is not supported.")
try:
hostname, ip, access_ip = host.split(',')
except Exception:
hostname, ip = host.split(',')
access_ip = ip
if self.exists_hostname(all_hosts, host):
self.debug("Skipping existing host {0}.".format(host))
continue
elif self.exists_ip(all_hosts, ip):
self.debug("Skipping existing host {0}.".format(ip))
continue
all_hosts[hostname] = {'ansible_host': access_ip,
'ip': ip,
'access_ip': access_ip}
return all_hosts return all_hosts
def range2ips(self, hosts):
reworked_hosts = []
def ips(start_address, end_address):
try:
# Python 3.x
start = int(ip_address(start_address))
end = int(ip_address(end_address))
except Exception:
# Python 2.7
start = int(ip_address(str(start_address)))
end = int(ip_address(str(end_address)))
return [ip_address(ip).exploded for ip in range(start, end + 1)]
for host in hosts:
if '-' in host and not host.startswith('-'):
start, end = host.strip().split('-')
try:
reworked_hosts.extend(ips(start, end))
except ValueError:
raise Exception("Range of ip_addresses isn't valid")
else:
reworked_hosts.append(host)
return reworked_hosts
def exists_hostname(self, existing_hosts, hostname): def exists_hostname(self, existing_hosts, hostname):
return hostname in existing_hosts.keys() return hostname in existing_hosts.keys()
@@ -256,34 +196,16 @@ class KubesprayInventory(object):
raise ValueError("Unable to find host by IP: {0}".format(ip)) raise ValueError("Unable to find host by IP: {0}".format(ip))
def purge_invalid_hosts(self, hostnames, protected_names=[]): def purge_invalid_hosts(self, hostnames, protected_names=[]):
for role in self.yaml_config['all']['children']: for role in self.config.sections():
if role != 'k8s-cluster' and self.yaml_config['all']['children'][role]['hosts']: # noqa for host, _ in self.config.items(role):
all_hosts = self.yaml_config['all']['children'][role]['hosts'].copy() # noqa
for host in all_hosts.keys():
if host not in hostnames and host not in protected_names:
self.debug(
"Host {0} removed from role {1}".format(host, role)) # noqa
del self.yaml_config['all']['children'][role]['hosts'][host] # noqa
# purge from all
if self.yaml_config['all']['hosts']:
all_hosts = self.yaml_config['all']['hosts'].copy()
for host in all_hosts.keys():
if host not in hostnames and host not in protected_names: if host not in hostnames and host not in protected_names:
self.debug("Host {0} removed from role all".format(host)) self.debug("Host {0} removed from role {1}".format(host,
del self.yaml_config['all']['hosts'][host] role))
self.config.remove_option(role, host)
def add_host_to_group(self, group, host, opts=""): def add_host_to_group(self, group, host, opts=""):
self.debug("adding host {0} to group {1}".format(host, group)) self.debug("adding host {0} to group {1}".format(host, group))
if group == 'all': self.config.set(group, host, opts)
if self.yaml_config['all']['hosts'] is None:
self.yaml_config['all']['hosts'] = {host: None}
self.yaml_config['all']['hosts'][host] = opts
elif group != 'k8s-cluster:children':
if self.yaml_config['all']['children'][group]['hosts'] is None:
self.yaml_config['all']['children'][group]['hosts'] = {
host: None}
else:
self.yaml_config['all']['children'][group]['hosts'][host] = None # noqa
def set_kube_master(self, hosts): def set_kube_master(self, hosts):
for host in hosts: for host in hosts:
@@ -294,31 +216,31 @@ class KubesprayInventory(object):
self.add_host_to_group('all', host, opts) self.add_host_to_group('all', host, opts)
def set_k8s_cluster(self): def set_k8s_cluster(self):
k8s_cluster = {'children': {'kube-master': None, 'kube-node': None}} self.add_host_to_group('k8s-cluster:children', 'kube-node')
self.yaml_config['all']['children']['k8s-cluster'] = k8s_cluster self.add_host_to_group('k8s-cluster:children', 'kube-master')
def set_calico_rr(self, hosts): def set_calico_rr(self, hosts):
for host in hosts: for host in hosts:
if host in self.yaml_config['all']['children']['kube-master']: if host in self.config.items('kube-master'):
self.debug("Not adding {0} to calico-rr group because it " self.debug("Not adding {0} to calico-rr group because it "
"conflicts with kube-master group".format(host)) "conflicts with kube-master group".format(host))
continue continue
if host in self.yaml_config['all']['children']['kube-node']: if host in self.config.items('kube-node'):
self.debug("Not adding {0} to calico-rr group because it " self.debug("Not adding {0} to calico-rr group because it "
"conflicts with kube-node group".format(host)) "conflicts with kube-node group".format(host))
continue continue
self.add_host_to_group('calico-rr', host) self.add_host_to_group('calico-rr', host)
def set_kube_node(self, hosts): def set_kube_node(self, hosts):
for host in hosts: for host in hosts:
if len(self.yaml_config['all']['hosts']) >= SCALE_THRESHOLD: if len(self.config['all']) >= SCALE_THRESHOLD:
if host in self.yaml_config['all']['children']['etcd']['hosts']: # noqa if self.config.has_option('etcd', host):
self.debug("Not adding {0} to kube-node group because of " self.debug("Not adding {0} to kube-node group because of "
"scale deployment and host is in etcd " "scale deployment and host is in etcd "
"group.".format(host)) "group.".format(host))
continue continue
if len(self.yaml_config['all']['hosts']) >= MASSIVE_SCALE_THRESHOLD: # noqa if len(self.config['all']) >= MASSIVE_SCALE_THRESHOLD:
if host in self.yaml_config['all']['children']['kube-master']['hosts']: # noqa if self.config.has_option('kube-master', host):
self.debug("Not adding {0} to kube-node group because of " self.debug("Not adding {0} to kube-node group because of "
"scale deployment and host is in kube-master " "scale deployment and host is in kube-master "
"group.".format(host)) "group.".format(host))
@@ -328,31 +250,42 @@ class KubesprayInventory(object):
def set_etcd(self, hosts): def set_etcd(self, hosts):
for host in hosts: for host in hosts:
self.add_host_to_group('etcd', host) self.add_host_to_group('etcd', host)
self.add_host_to_group('vault', host)
def load_file(self, files=None): def load_file(self, files=None):
'''Directly loads JSON to inventory.''' '''Directly loads JSON, or YAML file to inventory.'''
if not files: if not files:
raise Exception("No input file specified.") raise Exception("No input file specified.")
import json import json
import yaml
for filename in list(files): for filename in list(files):
# Try JSON # Try JSON, then YAML
try: try:
with open(filename, 'r') as f: with open(filename, 'r') as f:
data = json.load(f) data = json.load(f)
except ValueError: except ValueError:
raise Exception("Cannot read %s as JSON, or CSV", filename) try:
with open(filename, 'r') as f:
data = yaml.load(f)
print("yaml")
except ValueError:
raise Exception("Cannot read %s as JSON, YAML, or CSV",
filename)
self.ensure_required_groups(ROLES) self.ensure_required_groups(ROLES)
self.set_k8s_cluster() self.set_k8s_cluster()
for group, hosts in data.items(): for group, hosts in data.items():
self.ensure_required_groups([group]) self.ensure_required_groups([group])
for host, opts in hosts.items(): for host, opts in hosts.items():
optstring = {'ansible_host': opts['ip'], optstring = "ansible_host={0} ip={0}".format(opts['ip'])
'ip': opts['ip'], for key, val in opts.items():
'access_ip': opts['ip']} if key == "ip":
continue
optstring += " {0}={1}".format(key, val)
self.add_host_to_group('all', host, optstring) self.add_host_to_group('all', host, optstring)
self.add_host_to_group(group, host) self.add_host_to_group(group, host)
self.write_config(self.config_file) self.write_config(self.config_file)
@@ -364,8 +297,6 @@ class KubesprayInventory(object):
self.print_config() self.print_config()
elif command == 'print_ips': elif command == 'print_ips':
self.print_ips() self.print_ips()
elif command == 'print_hostnames':
self.print_hostnames()
elif command == 'load': elif command == 'load':
self.load_file(args) self.load_file(args)
else: else:
@@ -379,34 +310,27 @@ Available commands:
help - Display this message help - Display this message
print_cfg - Write inventory file to stdout print_cfg - Write inventory file to stdout
print_ips - Write a space-delimited list of IPs from "all" group print_ips - Write a space-delimited list of IPs from "all" group
print_hostnames - Write a space-delimited list of Hostnames from "all" group
Advanced usage: Advanced usage:
Add another host after initial creation: inventory.py 10.10.1.5 Add another host after initial creation: inventory.py 10.10.1.5
Add range of hosts: inventory.py 10.10.1.3-10.10.1.5
Add hosts with different ip and access ip: inventory.py 10.0.0.1,192.168.10.1 10.0.0.2,192.168.10.2 10.0.0.3,192.168.10.3
Add hosts with a specific hostname, ip, and optional access ip: first,10.0.0.1,192.168.10.1 second,10.0.0.2 last,10.0.0.3
Delete a host: inventory.py -10.10.1.3 Delete a host: inventory.py -10.10.1.3
Delete a host by id: inventory.py -node1 Delete a host by id: inventory.py -node1
Configurable env vars: 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.ini
HOST_PREFIX Host prefix for generated hosts. Default: node HOST_PREFIX Host prefix for generated hosts. Default: node
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 '''
print(help_text) print(help_text)
def print_config(self): def print_config(self):
yaml.dump(self.yaml_config, sys.stdout) self.config.write(sys.stdout)
def print_hostnames(self):
print(' '.join(self.yaml_config['all']['hosts'].keys()))
def print_ips(self): def print_ips(self):
ips = [] ips = []
for host, opts in self.yaml_config['all']['hosts'].items(): for host, opts in self.config.items('all'):
ips.append(self.get_ip_from_opts(opts)) ips.append(self.get_ip_from_opts(opts))
print(' '.join(ips)) print(' '.join(ips))
@@ -416,6 +340,5 @@ def main(argv=None):
argv = sys.argv[1:] argv = sys.argv[1:]
KubesprayInventory(argv, CONFIG_FILE) KubesprayInventory(argv, CONFIG_FILE)
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(main()) sys.exit(main())

View File

@@ -1,3 +1 @@
configparser>=3.3.0 configparser>=3.3.0
ruamel.yaml>=0.15.88
ipaddress

View File

@@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import inventory
import mock import mock
import unittest import unittest
@@ -23,7 +22,7 @@ path = "./contrib/inventory_builder/"
if path not in sys.path: if path not in sys.path:
sys.path.append(path) sys.path.append(path)
import inventory # noqa import inventory
class TestInventory(unittest.TestCase): class TestInventory(unittest.TestCase):
@@ -35,23 +34,21 @@ class TestInventory(unittest.TestCase):
self.inv = inventory.KubesprayInventory() self.inv = inventory.KubesprayInventory()
def test_get_ip_from_opts(self): def test_get_ip_from_opts(self):
optstring = {'ansible_host': '10.90.3.2', optstring = "ansible_host=10.90.3.2 ip=10.90.3.2"
'ip': '10.90.3.2',
'access_ip': '10.90.3.2'}
expected = "10.90.3.2" expected = "10.90.3.2"
result = self.inv.get_ip_from_opts(optstring) result = self.inv.get_ip_from_opts(optstring)
self.assertEqual(expected, result) self.assertEqual(expected, result)
def test_get_ip_from_opts_invalid(self): def test_get_ip_from_opts_invalid(self):
optstring = "notanaddr=value something random!chars:D" optstring = "notanaddr=value something random!chars:D"
self.assertRaisesRegex(ValueError, "IP parameter not found", self.assertRaisesRegexp(ValueError, "IP parameter not found",
self.inv.get_ip_from_opts, optstring) self.inv.get_ip_from_opts, optstring)
def test_ensure_required_groups(self): def test_ensure_required_groups(self):
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.assertTrue(group in self.inv.yaml_config['all']['children']) self.assertTrue(group in self.inv.config.sections())
def test_get_host_id(self): def test_get_host_id(self):
hostnames = ['node99', 'no99de01', '01node01', 'node1.domain', hostnames = ['node99', 'no99de01', '01node01', 'node1.domain',
@@ -64,55 +61,41 @@ class TestInventory(unittest.TestCase):
def test_get_host_id_invalid(self): def test_get_host_id_invalid(self):
bad_hostnames = ['node', 'no99de', '01node', 'node.111111'] bad_hostnames = ['node', 'no99de', '01node', 'node.111111']
for hostname in bad_hostnames: for hostname in bad_hostnames:
self.assertRaisesRegex(ValueError, "Host name must end in an", self.assertRaisesRegexp(ValueError, "Host name must end in an",
self.inv.get_host_id, hostname) self.inv.get_host_id, hostname)
def test_build_hostnames_add_one(self): def test_build_hostnames_add_one(self):
changed_hosts = ['10.90.0.2'] changed_hosts = ['10.90.0.2']
expected = OrderedDict([('node1', expected = OrderedDict([('node1',
{'ansible_host': '10.90.0.2', 'ansible_host=10.90.0.2 ip=10.90.0.2')])
'ip': '10.90.0.2',
'access_ip': '10.90.0.2'})])
result = self.inv.build_hostnames(changed_hosts) result = self.inv.build_hostnames(changed_hosts)
self.assertEqual(expected, result) self.assertEqual(expected, result)
def test_build_hostnames_add_duplicate(self): def test_build_hostnames_add_duplicate(self):
changed_hosts = ['10.90.0.2'] changed_hosts = ['10.90.0.2']
expected = OrderedDict([('node1', expected = OrderedDict([('node1',
{'ansible_host': '10.90.0.2', 'ansible_host=10.90.0.2 ip=10.90.0.2')])
'ip': '10.90.0.2', self.inv.config['all'] = expected
'access_ip': '10.90.0.2'})])
self.inv.yaml_config['all']['hosts'] = expected
result = self.inv.build_hostnames(changed_hosts) result = self.inv.build_hostnames(changed_hosts)
self.assertEqual(expected, result) self.assertEqual(expected, result)
def test_build_hostnames_add_two(self): def test_build_hostnames_add_two(self):
changed_hosts = ['10.90.0.2', '10.90.0.3'] changed_hosts = ['10.90.0.2', '10.90.0.3']
expected = OrderedDict([ expected = OrderedDict([
('node1', {'ansible_host': '10.90.0.2', ('node1', 'ansible_host=10.90.0.2 ip=10.90.0.2'),
'ip': '10.90.0.2', ('node2', 'ansible_host=10.90.0.3 ip=10.90.0.3')])
'access_ip': '10.90.0.2'}), self.inv.config['all'] = OrderedDict()
('node2', {'ansible_host': '10.90.0.3',
'ip': '10.90.0.3',
'access_ip': '10.90.0.3'})])
self.inv.yaml_config['all']['hosts'] = OrderedDict()
result = self.inv.build_hostnames(changed_hosts) result = self.inv.build_hostnames(changed_hosts)
self.assertEqual(expected, result) self.assertEqual(expected, result)
def test_build_hostnames_delete_first(self): def test_build_hostnames_delete_first(self):
changed_hosts = ['-10.90.0.2'] changed_hosts = ['-10.90.0.2']
existing_hosts = OrderedDict([ existing_hosts = OrderedDict([
('node1', {'ansible_host': '10.90.0.2', ('node1', 'ansible_host=10.90.0.2 ip=10.90.0.2'),
'ip': '10.90.0.2', ('node2', 'ansible_host=10.90.0.3 ip=10.90.0.3')])
'access_ip': '10.90.0.2'}), self.inv.config['all'] = existing_hosts
('node2', {'ansible_host': '10.90.0.3',
'ip': '10.90.0.3',
'access_ip': '10.90.0.3'})])
self.inv.yaml_config['all']['hosts'] = existing_hosts
expected = OrderedDict([ expected = OrderedDict([
('node2', {'ansible_host': '10.90.0.3', ('node2', 'ansible_host=10.90.0.3 ip=10.90.0.3')])
'ip': '10.90.0.3',
'access_ip': '10.90.0.3'})])
result = self.inv.build_hostnames(changed_hosts) result = self.inv.build_hostnames(changed_hosts)
self.assertEqual(expected, result) self.assertEqual(expected, result)
@@ -120,12 +103,8 @@ class TestInventory(unittest.TestCase):
hostname = 'node1' hostname = 'node1'
expected = True expected = True
existing_hosts = OrderedDict([ existing_hosts = OrderedDict([
('node1', {'ansible_host': '10.90.0.2', ('node1', 'ansible_host=10.90.0.2 ip=10.90.0.2'),
'ip': '10.90.0.2', ('node2', 'ansible_host=10.90.0.3 ip=10.90.0.3')])
'access_ip': '10.90.0.2'}),
('node2', {'ansible_host': '10.90.0.3',
'ip': '10.90.0.3',
'access_ip': '10.90.0.3'})])
result = self.inv.exists_hostname(existing_hosts, hostname) result = self.inv.exists_hostname(existing_hosts, hostname)
self.assertEqual(expected, result) self.assertEqual(expected, result)
@@ -133,12 +112,8 @@ class TestInventory(unittest.TestCase):
hostname = 'node99' hostname = 'node99'
expected = False expected = False
existing_hosts = OrderedDict([ existing_hosts = OrderedDict([
('node1', {'ansible_host': '10.90.0.2', ('node1', 'ansible_host=10.90.0.2 ip=10.90.0.2'),
'ip': '10.90.0.2', ('node2', 'ansible_host=10.90.0.3 ip=10.90.0.3')])
'access_ip': '10.90.0.2'}),
('node2', {'ansible_host': '10.90.0.3',
'ip': '10.90.0.3',
'access_ip': '10.90.0.3'})])
result = self.inv.exists_hostname(existing_hosts, hostname) result = self.inv.exists_hostname(existing_hosts, hostname)
self.assertEqual(expected, result) self.assertEqual(expected, result)
@@ -146,12 +121,8 @@ class TestInventory(unittest.TestCase):
ip = '10.90.0.2' ip = '10.90.0.2'
expected = True expected = True
existing_hosts = OrderedDict([ existing_hosts = OrderedDict([
('node1', {'ansible_host': '10.90.0.2', ('node1', 'ansible_host=10.90.0.2 ip=10.90.0.2'),
'ip': '10.90.0.2', ('node2', 'ansible_host=10.90.0.3 ip=10.90.0.3')])
'access_ip': '10.90.0.2'}),
('node2', {'ansible_host': '10.90.0.3',
'ip': '10.90.0.3',
'access_ip': '10.90.0.3'})])
result = self.inv.exists_ip(existing_hosts, ip) result = self.inv.exists_ip(existing_hosts, ip)
self.assertEqual(expected, result) self.assertEqual(expected, result)
@@ -159,112 +130,86 @@ class TestInventory(unittest.TestCase):
ip = '10.90.0.200' ip = '10.90.0.200'
expected = False expected = False
existing_hosts = OrderedDict([ existing_hosts = OrderedDict([
('node1', {'ansible_host': '10.90.0.2', ('node1', 'ansible_host=10.90.0.2 ip=10.90.0.2'),
'ip': '10.90.0.2', ('node2', 'ansible_host=10.90.0.3 ip=10.90.0.3')])
'access_ip': '10.90.0.2'}),
('node2', {'ansible_host': '10.90.0.3',
'ip': '10.90.0.3',
'access_ip': '10.90.0.3'})])
result = self.inv.exists_ip(existing_hosts, ip) result = self.inv.exists_ip(existing_hosts, ip)
self.assertEqual(expected, result) self.assertEqual(expected, result)
def test_delete_host_by_ip_positive(self): def test_delete_host_by_ip_positive(self):
ip = '10.90.0.2' ip = '10.90.0.2'
expected = OrderedDict([ expected = OrderedDict([
('node2', {'ansible_host': '10.90.0.3', ('node2', 'ansible_host=10.90.0.3 ip=10.90.0.3')])
'ip': '10.90.0.3',
'access_ip': '10.90.0.3'})])
existing_hosts = OrderedDict([ existing_hosts = OrderedDict([
('node1', {'ansible_host': '10.90.0.2', ('node1', 'ansible_host=10.90.0.2 ip=10.90.0.2'),
'ip': '10.90.0.2', ('node2', 'ansible_host=10.90.0.3 ip=10.90.0.3')])
'access_ip': '10.90.0.2'}),
('node2', {'ansible_host': '10.90.0.3',
'ip': '10.90.0.3',
'access_ip': '10.90.0.3'})])
self.inv.delete_host_by_ip(existing_hosts, ip) self.inv.delete_host_by_ip(existing_hosts, ip)
self.assertEqual(expected, existing_hosts) self.assertEqual(expected, existing_hosts)
def test_delete_host_by_ip_negative(self): def test_delete_host_by_ip_negative(self):
ip = '10.90.0.200' ip = '10.90.0.200'
existing_hosts = OrderedDict([ existing_hosts = OrderedDict([
('node1', {'ansible_host': '10.90.0.2', ('node1', 'ansible_host=10.90.0.2 ip=10.90.0.2'),
'ip': '10.90.0.2', ('node2', 'ansible_host=10.90.0.3 ip=10.90.0.3')])
'access_ip': '10.90.0.2'}), self.assertRaisesRegexp(ValueError, "Unable to find host",
('node2', {'ansible_host': '10.90.0.3', self.inv.delete_host_by_ip, existing_hosts, ip)
'ip': '10.90.0.3',
'access_ip': '10.90.0.3'})])
self.assertRaisesRegex(ValueError, "Unable to find host",
self.inv.delete_host_by_ip, existing_hosts, ip)
def test_purge_invalid_hosts(self): def test_purge_invalid_hosts(self):
proper_hostnames = ['node1', 'node2'] proper_hostnames = ['node1', 'node2']
bad_host = 'doesnotbelong2' bad_host = 'doesnotbelong2'
existing_hosts = OrderedDict([ existing_hosts = OrderedDict([
('node1', {'ansible_host': '10.90.0.2', ('node1', 'ansible_host=10.90.0.2 ip=10.90.0.2'),
'ip': '10.90.0.2', ('node2', 'ansible_host=10.90.0.3 ip=10.90.0.3'),
'access_ip': '10.90.0.2'}), ('doesnotbelong2', 'whateveropts=ilike')])
('node2', {'ansible_host': '10.90.0.3', self.inv.config['all'] = existing_hosts
'ip': '10.90.0.3',
'access_ip': '10.90.0.3'}),
('doesnotbelong2', {'whateveropts=ilike'})])
self.inv.yaml_config['all']['hosts'] = existing_hosts
self.inv.purge_invalid_hosts(proper_hostnames) self.inv.purge_invalid_hosts(proper_hostnames)
self.assertTrue( self.assertTrue(bad_host not in self.inv.config['all'].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'
host = 'node1' host = 'node1'
opts = {'ip': '10.90.0.2'} opts = 'ip=10.90.0.2'
self.inv.add_host_to_group(group, host, opts) self.inv.add_host_to_group(group, host, opts)
self.assertEqual( self.assertEqual(self.inv.config[group].get(host), opts)
self.inv.yaml_config['all']['children'][group]['hosts'].get(host),
None)
def test_set_kube_master(self): def test_set_kube_master(self):
group = 'kube-master' group = 'kube-master'
host = 'node1' host = 'node1'
self.inv.set_kube_master([host]) self.inv.set_kube_master([host])
self.assertTrue( self.assertTrue(host in self.inv.config[group])
host in self.inv.yaml_config['all']['children'][group]['hosts'])
def test_set_all(self): def test_set_all(self):
group = 'all'
hosts = OrderedDict([ hosts = OrderedDict([
('node1', 'opt1'), ('node1', 'opt1'),
('node2', 'opt2')]) ('node2', 'opt2')])
self.inv.set_all(hosts) self.inv.set_all(hosts)
for host, opt in hosts.items(): for host, opt in hosts.items():
self.assertEqual( self.assertEqual(self.inv.config[group].get(host), opt)
self.inv.yaml_config['all']['hosts'].get(host), opt)
def test_set_k8s_cluster(self): def test_set_k8s_cluster(self):
group = 'k8s-cluster' group = 'k8s-cluster:children'
expected_hosts = ['kube-node', 'kube-master'] expected_hosts = ['kube-node', 'kube-master']
self.inv.set_k8s_cluster() self.inv.set_k8s_cluster()
for host in expected_hosts: for host in expected_hosts:
self.assertTrue( self.assertTrue(host in self.inv.config[group])
host in
self.inv.yaml_config['all']['children'][group]['children'])
def test_set_kube_node(self): def test_set_kube_node(self):
group = 'kube-node' group = 'kube-node'
host = 'node1' host = 'node1'
self.inv.set_kube_node([host]) self.inv.set_kube_node([host])
self.assertTrue( self.assertTrue(host in self.inv.config[group])
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.assertTrue( self.assertTrue(host in self.inv.config[group])
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
@@ -274,13 +219,11 @@ class TestInventory(unittest.TestCase):
hosts["node" + str(hostid)] = "" hosts["node" + str(hostid)] = ""
self.inv.set_all(hosts) self.inv.set_all(hosts)
self.inv.set_etcd(list(hosts.keys())[0:3]) self.inv.set_etcd(hosts.keys()[0:3])
self.inv.set_kube_master(list(hosts.keys())[0:2]) self.inv.set_kube_master(hosts.keys()[0:2])
self.inv.set_kube_node(hosts.keys()) self.inv.set_kube_node(hosts.keys())
for h in range(3): for h in range(3):
self.assertFalse( self.assertFalse(hosts.keys()[h] in self.inv.config['kube-node'])
list(hosts.keys())[h] in
self.inv.yaml_config['all']['children']['kube-node']['hosts'])
def test_scale_scenario_two(self): def test_scale_scenario_two(self):
num_nodes = 500 num_nodes = 500
@@ -290,57 +233,8 @@ class TestInventory(unittest.TestCase):
hosts["node" + str(hostid)] = "" hosts["node" + str(hostid)] = ""
self.inv.set_all(hosts) self.inv.set_all(hosts)
self.inv.set_etcd(list(hosts.keys())[0:3]) self.inv.set_etcd(hosts.keys()[0:3])
self.inv.set_kube_master(list(hosts.keys())[3:5]) self.inv.set_kube_master(hosts.keys()[3:5])
self.inv.set_kube_node(hosts.keys()) self.inv.set_kube_node(hosts.keys())
for h in range(5): for h in range(5):
self.assertFalse( self.assertFalse(hosts.keys()[h] in self.inv.config['kube-node'])
list(hosts.keys())[h] in
self.inv.yaml_config['all']['children']['kube-node']['hosts'])
def test_range2ips_range(self):
changed_hosts = ['10.90.0.2', '10.90.0.4-10.90.0.6', '10.90.0.8']
expected = ['10.90.0.2',
'10.90.0.4',
'10.90.0.5',
'10.90.0.6',
'10.90.0.8']
result = self.inv.range2ips(changed_hosts)
self.assertEqual(expected, result)
def test_range2ips_incorrect_range(self):
host_range = ['10.90.0.4-a.9b.c.e']
self.assertRaisesRegex(Exception, "Range of ip_addresses isn't valid",
self.inv.range2ips, host_range)
def test_build_hostnames_different_ips_add_one(self):
changed_hosts = ['10.90.0.2,192.168.0.2']
expected = OrderedDict([('node1',
{'ansible_host': '192.168.0.2',
'ip': '10.90.0.2',
'access_ip': '192.168.0.2'})])
result = self.inv.build_hostnames(changed_hosts)
self.assertEqual(expected, result)
def test_build_hostnames_different_ips_add_duplicate(self):
changed_hosts = ['10.90.0.2,192.168.0.2']
expected = OrderedDict([('node1',
{'ansible_host': '192.168.0.2',
'ip': '10.90.0.2',
'access_ip': '192.168.0.2'})])
self.inv.yaml_config['all']['hosts'] = expected
result = self.inv.build_hostnames(changed_hosts)
self.assertEqual(expected, result)
def test_build_hostnames_different_ips_add_two(self):
changed_hosts = ['10.90.0.2,192.168.0.2', '10.90.0.3,192.168.0.3']
expected = OrderedDict([
('node1', {'ansible_host': '192.168.0.2',
'ip': '10.90.0.2',
'access_ip': '192.168.0.2'}),
('node2', {'ansible_host': '192.168.0.3',
'ip': '10.90.0.3',
'access_ip': '192.168.0.3'})])
self.inv.yaml_config['all']['hosts'] = OrderedDict()
result = self.inv.build_hostnames(changed_hosts)
self.assertEqual(expected, result)

View File

@@ -1,7 +1,7 @@
[tox] [tox]
minversion = 1.6 minversion = 1.6
skipsdist = True skipsdist = True
envlist = pep8, py33 envlist = pep8, py27
[testenv] [testenv]
whitelist_externals = py.test whitelist_externals = py.test

View File

@@ -1,9 +1,15 @@
--- ---
- name: Upgrade all packages to the latest version (yum)
yum:
name: '*'
state: latest
when: ansible_os_family == "RedHat"
- name: Install required packages - name: Install required packages
yum: yum:
name: "{{ item }}" name: "{{ item }}"
state: present state: latest
with_items: with_items:
- bind-utils - bind-utils
- ntp - ntp
@@ -15,13 +21,23 @@
update_cache: yes update_cache: yes
cache_valid_time: 3600 cache_valid_time: 3600
name: "{{ item }}" name: "{{ item }}"
state: present state: latest
install_recommends: no install_recommends: no
with_items: with_items:
- dnsutils - dnsutils
- ntp - ntp
when: ansible_os_family == "Debian" when: ansible_os_family == "Debian"
- name: Upgrade all packages to the latest version (apt)
shell: apt-get -o \
Dpkg::Options::=--force-confdef -o \
Dpkg::Options::=--force-confold -q -y \
dist-upgrade
environment:
DEBIAN_FRONTEND: noninteractive
when: ansible_os_family == "Debian"
# Create deployment user if required # Create deployment user if required
- include: user.yml - include: user.yml
when: k8s_deployment_user is defined when: k8s_deployment_user is defined

View File

@@ -2,11 +2,9 @@
``` ```
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. 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. This playbook aims to automate [this](https://metallb.universe.tf/tutorial/layer2/tutorial). It deploys MetalLB into kubernetes and sets up a layer 2 loadbalancer.
## Install ## 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/k8s_heketi_inventory.yml contrib/metallb/metallb.yml
ansible-playbook --ask-become -i inventory/sample/hosts.ini contrib/metallb/metallb.yml
``` ```

View File

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

View File

@@ -1,12 +1,6 @@
--- ---
- hosts: bastion[0]
gather_facts: False
roles:
- { role: kubespray-defaults}
- { role: bastion-ssh-config, tags: ["localhost", "bastion"]}
- hosts: kube-master[0] - hosts: kube-master[0]
tags: tags:
- "provision" - "provision"
roles: roles:
- { role: kubespray-defaults}
- { role: provision } - { role: provision }

View File

@@ -1,16 +1,7 @@
--- ---
metallb: metallb:
ip_range: ip_range: "10.5.0.50-10.5.0.99"
- "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: limits:
cpu: "100m" cpu: "100m"
memory: "100Mi" memory: "100Mi"
port: "7472" port: "7472"
version: v0.7.3

View File

@@ -1,25 +1,4 @@
--- ---
- 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 | Check AppArmor status
command: which apparmor_parser
register: apparmor_status
when:
- podsecuritypolicy_enabled
- inventory_hostname == groups['kube-master'][0]
failed_when: false
- name: Kubernetes Apps | Set apparmor_enabled
set_fact:
apparmor_enabled: "{{ apparmor_status.rc == 0 }}"
when:
- podsecuritypolicy_enabled
- inventory_hostname == groups['kube-master'][0]
- name: "Kubernetes Apps | Lay Down MetalLB" - name: "Kubernetes Apps | Lay Down MetalLB"
become: true become: true
template: { src: "{{ item }}.j2", dest: "{{ kube_config_dir }}/{{ item }}" } template: { src: "{{ item }}.j2", dest: "{{ kube_config_dir }}/{{ item }}" }
@@ -27,14 +6,12 @@
register: "rendering" register: "rendering"
when: when:
- "inventory_hostname == groups['kube-master'][0]" - "inventory_hostname == groups['kube-master'][0]"
- name: "Kubernetes Apps | Install and configure MetalLB" - name: "Kubernetes Apps | Install and configure MetalLB"
kube: kube:
name: "MetalLB" name: "MetalLB"
kubectl: "{{ bin_dir }}/kubectl" kubectl: "{{bin_dir}}/kubectl"
filename: "{{ kube_config_dir }}/{{ item.item }}" filename: "{{ kube_config_dir }}/{{ item.item }}"
state: "{{ item.changed | ternary('latest','present') }}" state: "{{ item.changed | ternary('latest','present') }}"
become: true
with_items: "{{ rendering.results }}" with_items: "{{ rendering.results }}"
when: when:
- "inventory_hostname == groups['kube-master'][0]" - "inventory_hostname == groups['kube-master'][0]"

View File

@@ -8,18 +8,6 @@ data:
config: | config: |
address-pools: address-pools:
- name: loadbalanced - name: loadbalanced
protocol: {{ metallb.protocol }} protocol: layer2
addresses: addresses:
{% for ip_range in metallb.ip_range %} - {{ metallb.ip_range }}
- {{ ip_range }}
{% endfor %}
{% if metallb.additional_address_pools is defined %}{% for pool in metallb.additional_address_pools %}
- name: {{ pool }}
protocol: {{ metallb.additional_address_pools[pool].protocol }}
addresses:
{% for ip_range in metallb.additional_address_pools[pool].ip_range %}
- {{ ip_range }}
{% endfor %}
auto-assign: {{ metallb.additional_address_pools[pool].auto_assign }}
{% endfor %}
{% endif %}

View File

@@ -50,48 +50,22 @@ rules:
- apiGroups: [""] - apiGroups: [""]
resources: ["services", "endpoints", "nodes"] resources: ["services", "endpoints", "nodes"]
verbs: ["get", "list", "watch"] verbs: ["get", "list", "watch"]
{% if podsecuritypolicy_enabled %}
- apiGroups: ["policy"]
resourceNames: ["metallb"]
resources: ["podsecuritypolicies"]
verbs: ["use"]
--- ---
apiVersion: policy/v1beta1 apiVersion: rbac.authorization.k8s.io/v1
kind: PodSecurityPolicy kind: Role
metadata: metadata:
name: metallb namespace: metallb-system
annotations: name: leader-election
seccomp.security.alpha.kubernetes.io/defaultProfileName: 'docker/default'
seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'docker/default'
{% if apparmor_enabled %}
apparmor.security.beta.kubernetes.io/defaultProfileName: 'runtime/default'
apparmor.security.beta.kubernetes.io/allowedProfileNames: 'runtime/default'
{% endif %}
labels: labels:
app: metallb app: metallb
spec: rules:
privileged: true - apiGroups: [""]
allowPrivilegeEscalation: false resources: ["endpoints"]
allowedCapabilities: resourceNames: ["metallb-speaker"]
- net_raw verbs: ["get", "update"]
volumes: - apiGroups: [""]
- secret resources: ["endpoints"]
hostNetwork: true verbs: ["create"]
hostPorts:
- min: {{ metallb.port }}
max: {{ metallb.port }}
hostIPC: false
hostPID: false
runAsUser:
rule: 'RunAsAny'
seLinux:
rule: 'RunAsAny'
supplementalGroups:
rule: 'RunAsAny'
fsGroup:
rule: 'RunAsAny'
readOnlyRootFilesystem: true
{% endif %}
--- ---
apiVersion: rbac.authorization.k8s.io/v1 apiVersion: rbac.authorization.k8s.io/v1
kind: Role kind: Role
@@ -157,7 +131,22 @@ roleRef:
kind: Role kind: Role
name: config-watcher name: config-watcher
--- ---
apiVersion: apps/v1 apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
namespace: metallb-system
name: leader-election
labels:
app: metallb
subjects:
- kind: ServiceAccount
name: speaker
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: leader-election
---
apiVersion: apps/v1beta2
kind: DaemonSet kind: DaemonSet
metadata: metadata:
namespace: metallb-system namespace: metallb-system
@@ -184,7 +173,7 @@ spec:
hostNetwork: true hostNetwork: true
containers: containers:
- name: speaker - name: speaker
image: metallb/speaker:{{ metallb.version }} image: metallb/speaker:v0.6.2
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
args: args:
- --port={{ metallb.port }} - --port={{ metallb.port }}
@@ -211,7 +200,7 @@ spec:
- net_raw - net_raw
--- ---
apiVersion: apps/v1 apiVersion: apps/v1beta2
kind: Deployment kind: Deployment
metadata: metadata:
namespace: metallb-system namespace: metallb-system
@@ -241,7 +230,7 @@ spec:
runAsUser: 65534 # nobody runAsUser: 65534 # nobody
containers: containers:
- name: controller - name: controller
image: metallb/controller:{{ metallb.version }} image: metallb/controller:v0.6.2
imagePullPolicy: IfNotPresent imagePullPolicy: IfNotPresent
args: args:
- --port={{ metallb.port }} - --port={{ metallb.port }}
@@ -261,3 +250,5 @@ spec:
readOnlyRootFilesystem: true readOnlyRootFilesystem: true
--- ---

View File

@@ -1,15 +0,0 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: kubernetes-dashboard
labels:
k8s-app: kubernetes-dashboard
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: kubernetes-dashboard
namespace: kube-system

View File

@@ -4,7 +4,7 @@
vars: vars:
ansible_ssh_pipelining: false ansible_ssh_pipelining: false
roles: roles:
- { role: bootstrap-os, tags: bootstrap-os} - { role: bootstrap-os, tags: bootstrap-os}
- hosts: all - hosts: all
gather_facts: true gather_facts: true
@@ -22,3 +22,4 @@
- hosts: kube-master[0] - hosts: kube-master[0]
roles: roles:
- { role: kubernetes-pv } - { role: kubernetes-pv }

View File

@@ -21,7 +21,7 @@ You can specify a `default_release` for apt on Debian/Ubuntu by overriding this
glusterfs_ppa_use: yes glusterfs_ppa_use: yes
glusterfs_ppa_version: "3.5" glusterfs_ppa_version: "3.5"
For Ubuntu, specify whether to use the official Gluster PPA, and which version of the PPA to use. See Gluster's [Getting Started Guide](https://docs.gluster.org/en/latest/Quick-Start-Guide/Quickstart/) for more info. For Ubuntu, specify whether to use the official Gluster PPA, and which version of the PPA to use. See Gluster's [Getting Started Guide](http://www.gluster.org/community/documentation/index.php/Getting_started_install) for more info.
## Dependencies ## Dependencies

View File

@@ -22,9 +22,9 @@ galaxy_info:
- wheezy - wheezy
- jessie - jessie
galaxy_tags: galaxy_tags:
- system - system
- networking - networking
- cloud - cloud
- clustering - clustering
- files - files
- sharing - sharing

View File

@@ -12,5 +12,5 @@
- name: Ensure Gluster mount directories exist. - name: Ensure Gluster mount directories exist.
file: "path={{ item }} state=directory mode=0775" file: "path={{ item }} state=directory mode=0775"
with_items: with_items:
- "{{ gluster_mount_dir }}" - "{{ gluster_mount_dir }}"
when: ansible_os_family in ["Debian","RedHat"] and groups['gfs-cluster'] is defined when: ansible_os_family in ["Debian","RedHat"] and groups['gfs-cluster'] is defined

View File

@@ -22,9 +22,9 @@ galaxy_info:
- wheezy - wheezy
- jessie - jessie
galaxy_tags: galaxy_tags:
- system - system
- networking - networking
- cloud - cloud
- clustering - clustering
- files - files
- sharing - sharing

View File

@@ -3,7 +3,7 @@
- name: Include OS-specific variables. - name: Include OS-specific variables.
include_vars: "{{ ansible_os_family }}.yml" include_vars: "{{ ansible_os_family }}.yml"
# Install xfs package # Instal xfs package
- name: install xfs Debian - name: install xfs Debian
apt: name=xfsprogs state=present apt: name=xfsprogs state=present
when: ansible_os_family == "Debian" when: ansible_os_family == "Debian"
@@ -33,36 +33,24 @@
- name: Ensure Gluster brick and mount directories exist. - name: Ensure Gluster brick and mount directories exist.
file: "path={{ item }} state=directory mode=0775" file: "path={{ item }} state=directory mode=0775"
with_items: with_items:
- "{{ gluster_brick_dir }}" - "{{ gluster_brick_dir }}"
- "{{ gluster_mount_dir }}" - "{{ gluster_mount_dir }}"
- name: Configure Gluster volume with replicas - name: Configure Gluster volume.
gluster_volume: gluster_volume:
state: present state: present
name: "{{ gluster_brick_name }}" name: "{{ gluster_brick_name }}"
brick: "{{ gluster_brick_dir }}" brick: "{{ gluster_brick_dir }}"
replicas: "{{ groups['gfs-cluster'] | length }}" replicas: "{{ groups['gfs-cluster'] | length }}"
cluster: "{% for item in groups['gfs-cluster'] -%}{{ hostvars[item]['ip']|default(hostvars[item].ansible_default_ipv4['address']) }}{% if not loop.last %},{% endif %}{%- endfor %}" cluster: "{% for item in groups['gfs-cluster'] -%}{{ hostvars[item]['ip']|default(hostvars[item].ansible_default_ipv4['address']) }}{% if not loop.last %},{% endif %}{%- endfor %}"
host: "{{ inventory_hostname }}" host: "{{ inventory_hostname }}"
force: yes force: yes
run_once: true run_once: true
when: groups['gfs-cluster']|length > 1
- name: Configure Gluster volume without replicas
gluster_volume:
state: present
name: "{{ gluster_brick_name }}"
brick: "{{ gluster_brick_dir }}"
cluster: "{% for item in groups['gfs-cluster'] -%}{{ hostvars[item]['ip']|default(hostvars[item].ansible_default_ipv4['address']) }}{% if not loop.last %},{% endif %}{%- endfor %}"
host: "{{ inventory_hostname }}"
force: yes
run_once: true
when: groups['gfs-cluster']|length <= 1
- name: Mount glusterfs to retrieve disk size - name: Mount glusterfs to retrieve disk size
mount: mount:
name: "{{ gluster_mount_dir }}" name: "{{ gluster_mount_dir }}"
src: "{{ ip|default(ansible_default_ipv4['address']) }}:/gluster" src: "{{ ip|default(ansible_default_ipv4['address']) }}:/gluster"
fstype: glusterfs fstype: glusterfs
opts: "defaults,_netdev" opts: "defaults,_netdev"
state: mounted state: mounted
@@ -75,13 +63,13 @@
- name: Set Gluster disk size to variable - name: Set Gluster disk size to variable
set_fact: set_fact:
gluster_disk_size_gb: "{{ (mounts_data.ansible_facts.ansible_mounts | selectattr('mount', 'equalto', gluster_mount_dir) | map(attribute='size_total') | first | int / (1024*1024*1024)) | int }}" gluster_disk_size_gb: "{{ (mounts_data.ansible_facts.ansible_mounts | selectattr('mount', 'equalto', gluster_mount_dir) | map(attribute='size_total') | first | int / (1024*1024*1024)) | int }}"
when: groups['gfs-cluster'] is defined and inventory_hostname == groups['gfs-cluster'][0] when: groups['gfs-cluster'] is defined and inventory_hostname == groups['gfs-cluster'][0]
- name: Create file on GlusterFS - name: Create file on GlusterFS
template: template:
dest: "{{ gluster_mount_dir }}/.test-file.txt" dest: "{{ gluster_mount_dir }}/.test-file.txt"
src: test-file.txt src: test-file.txt
when: groups['gfs-cluster'] is defined and inventory_hostname == groups['gfs-cluster'][0] when: groups['gfs-cluster'] is defined and inventory_hostname == groups['gfs-cluster'][0]
- name: Unmount glusterfs - name: Unmount glusterfs
@@ -91,3 +79,4 @@
src: "{{ ip|default(ansible_default_ipv4['address']) }}:/gluster" src: "{{ ip|default(ansible_default_ipv4['address']) }}:/gluster"
state: unmounted state: unmounted
when: groups['gfs-cluster'] is defined and inventory_hostname == groups['gfs-cluster'][0] when: groups['gfs-cluster'] is defined and inventory_hostname == groups['gfs-cluster'][0]

View File

@@ -1,12 +1,10 @@
--- ---
- name: Kubernetes Apps | Lay Down k8s GlusterFS Endpoint and PV - name: Kubernetes Apps | Lay Down k8s GlusterFS Endpoint and PV
template: template: src={{item.file}} dest={{kube_config_dir}}/{{item.dest}}
src: "{{ item.file }}"
dest: "{{ kube_config_dir }}/{{ item.dest }}"
with_items: with_items:
- { file: glusterfs-kubernetes-endpoint.json.j2, type: ep, dest: glusterfs-kubernetes-endpoint.json} - { file: glusterfs-kubernetes-endpoint.json.j2, type: ep, dest: glusterfs-kubernetes-endpoint.json}
- { file: glusterfs-kubernetes-pv.yml.j2, type: pv, dest: glusterfs-kubernetes-pv.yml} - { file: glusterfs-kubernetes-pv.yml.j2, type: pv, dest: glusterfs-kubernetes-pv.yml}
- { file: glusterfs-kubernetes-endpoint-svc.json.j2, type: svc, dest: glusterfs-kubernetes-endpoint-svc.json} - { file: glusterfs-kubernetes-endpoint-svc.json.j2, type: svc, dest: glusterfs-kubernetes-endpoint-svc.json}
register: gluster_pv register: gluster_pv
when: inventory_hostname == groups['kube-master'][0] and groups['gfs-cluster'] is defined and hostvars[groups['gfs-cluster'][0]].gluster_disk_size_gb is defined when: inventory_hostname == groups['kube-master'][0] and groups['gfs-cluster'] is defined and hostvars[groups['gfs-cluster'][0]].gluster_disk_size_gb is defined
@@ -14,9 +12,9 @@
kube: kube:
name: glusterfs name: glusterfs
namespace: default namespace: default
kubectl: "{{ bin_dir }}/kubectl" kubectl: "{{bin_dir}}/kubectl"
resource: "{{ item.item.type }}" resource: "{{item.item.type}}"
filename: "{{ kube_config_dir }}/{{ item.item.dest }}" filename: "{{kube_config_dir}}/{{item.item.dest}}"
state: "{{ item.changed | ternary('latest','present') }}" state: "{{item.changed | ternary('latest','present') }}"
with_items: "{{ gluster_pv.results }}" with_items: "{{ gluster_pv.results }}"
when: inventory_hostname == groups['kube-master'][0] and groups['gfs-cluster'] is defined when: inventory_hostname == groups['kube-master'][0] and groups['gfs-cluster'] is defined

View File

@@ -1,3 +1,2 @@
---
dependencies: dependencies:
- {role: kubernetes-pv/ansible, tags: apps} - {role: kubernetes-pv/ansible, tags: apps}

View File

@@ -14,5 +14,3 @@ ansible-playbook --ask-become -i inventory/sample/k8s_heketi_inventory.yml contr
``` ```
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
``` ```
Add `--extra-vars "heketi_remove_lvm=true"` to the command above to remove LVM packages from the system

View File

@@ -2,23 +2,23 @@
- name: "Load lvm kernel modules" - name: "Load lvm kernel modules"
become: true become: true
with_items: with_items:
- "dm_snapshot" - "dm_snapshot"
- "dm_mirror" - "dm_mirror"
- "dm_thin_pool" - "dm_thin_pool"
modprobe: modprobe:
name: "{{ item }}" name: "{{ item }}"
state: "present" state: "present"
- name: "Install glusterfs mount utils (RedHat)" - name: "Install glusterfs mount utils (RedHat)"
become: true become: true
yum: yum:
name: "glusterfs-fuse" name: "glusterfs-fuse"
state: "present" state: "present"
when: "ansible_os_family == 'RedHat'" when: "ansible_os_family == 'RedHat'"
- name: "Install glusterfs mount utils (Debian)" - name: "Install glusterfs mount utils (Debian)"
become: true become: true
apt: apt:
name: "glusterfs-client" name: "glusterfs-client"
state: "present" state: "present"
when: "ansible_os_family == 'Debian'" when: "ansible_os_family == 'Debian'"

View File

@@ -1,10 +1,8 @@
---
# Bootstrap heketi # Bootstrap heketi
- name: "Get state of heketi service, deployment and pods." - name: "Get state of heketi service, deployment and pods."
register: "initial_heketi_state" register: "initial_heketi_state"
changed_when: false changed_when: false
command: "{{ bin_dir }}/kubectl get services,deployments,pods --selector=deploy-heketi --output=json" command: "{{ bin_dir }}/kubectl get services,deployments,pods --selector=deploy-heketi --output=json"
- name: "Bootstrap heketi." - name: "Bootstrap heketi."
when: when:
- "(initial_heketi_state.stdout|from_json|json_query(\"items[?kind=='Service']\"))|length == 0" - "(initial_heketi_state.stdout|from_json|json_query(\"items[?kind=='Service']\"))|length == 0"
@@ -17,20 +15,15 @@
register: "initial_heketi_pod" register: "initial_heketi_pod"
command: "{{ bin_dir }}/kubectl get pods --selector=deploy-heketi=pod,glusterfs=heketi-pod,name=deploy-heketi --output=json" command: "{{ bin_dir }}/kubectl get pods --selector=deploy-heketi=pod,glusterfs=heketi-pod,name=deploy-heketi --output=json"
changed_when: false changed_when: false
- name: "Ensure heketi bootstrap pod is up." - name: "Ensure heketi bootstrap pod is up."
assert: assert:
that: "(initial_heketi_pod.stdout|from_json|json_query('items[*]'))|length == 1" that: "(initial_heketi_pod.stdout|from_json|json_query('items[*]'))|length == 1"
- set_fact:
- name: Store the initial heketi pod name
set_fact:
initial_heketi_pod_name: "{{ initial_heketi_pod.stdout|from_json|json_query(\"items[*].metadata.name|[0]\") }}" initial_heketi_pod_name: "{{ initial_heketi_pod.stdout|from_json|json_query(\"items[*].metadata.name|[0]\") }}"
- name: "Test heketi topology." - name: "Test heketi topology."
changed_when: false changed_when: false
register: "heketi_topology" register: "heketi_topology"
command: "{{ bin_dir }}/kubectl exec {{ initial_heketi_pod_name }} -- heketi-cli --user admin --secret {{ heketi_admin_key }} topology info --json" command: "{{ bin_dir }}/kubectl exec {{ initial_heketi_pod_name }} -- heketi-cli --user admin --secret {{ heketi_admin_key }} topology info --json"
- name: "Load heketi topology." - name: "Load heketi topology."
when: "heketi_topology.stdout|from_json|json_query(\"clusters[*].nodes[*]\")|flatten|length == 0" when: "heketi_topology.stdout|from_json|json_query(\"clusters[*].nodes[*]\")|flatten|length == 0"
include_tasks: "bootstrap/topology.yml" include_tasks: "bootstrap/topology.yml"
@@ -48,7 +41,6 @@
command: "{{ bin_dir }}/kubectl get secrets,endpoints,services,jobs --output=json" command: "{{ bin_dir }}/kubectl get secrets,endpoints,services,jobs --output=json"
changed_when: false changed_when: false
register: "heketi_storage_state" register: "heketi_storage_state"
# ensure endpoints actually exist before trying to move database data to it # ensure endpoints actually exist before trying to move database data to it
- name: "Create heketi storage." - name: "Create heketi storage."
include_tasks: "bootstrap/storage.yml" include_tasks: "bootstrap/storage.yml"

View File

@@ -6,7 +6,7 @@
- name: "Kubernetes Apps | Install and configure Heketi Bootstrap" - name: "Kubernetes Apps | Install and configure Heketi Bootstrap"
kube: kube:
name: "GlusterFS" name: "GlusterFS"
kubectl: "{{ bin_dir }}/kubectl" kubectl: "{{bin_dir}}/kubectl"
filename: "{{ kube_config_dir }}/heketi-bootstrap.json" filename: "{{ kube_config_dir }}/heketi-bootstrap.json"
state: "{{ rendering.changed | ternary('latest', 'present') }}" state: "{{ rendering.changed | ternary('latest', 'present') }}"
- name: "Wait for heketi bootstrap to complete." - name: "Wait for heketi bootstrap to complete."
@@ -18,7 +18,7 @@
deployments_query: "items[?kind=='Deployment'].status.conditions|[0][?type=='Available'].status|[0]" deployments_query: "items[?kind=='Deployment'].status.conditions|[0][?type=='Available'].status|[0]"
command: "{{ bin_dir }}/kubectl get services,deployments,pods --selector=deploy-heketi --output=json" command: "{{ bin_dir }}/kubectl get services,deployments,pods --selector=deploy-heketi --output=json"
until: until:
- "initial_heketi_state.stdout|from_json|json_query(pods_query) == 'True'" - "initial_heketi_state.stdout|from_json|json_query(pods_query) == 'True'"
- "initial_heketi_state.stdout|from_json|json_query(deployments_query) == 'True'" - "initial_heketi_state.stdout|from_json|json_query(deployments_query) == 'True'"
retries: 60 retries: 60
delay: 5 delay: 5

View File

@@ -6,7 +6,7 @@
- name: "Create heketi storage." - name: "Create heketi storage."
kube: kube:
name: "GlusterFS" name: "GlusterFS"
kubectl: "{{ bin_dir }}/kubectl" kubectl: "{{bin_dir}}/kubectl"
filename: "{{ kube_config_dir }}/heketi-storage-bootstrap.json" filename: "{{ kube_config_dir }}/heketi-storage-bootstrap.json"
state: "present" state: "present"
vars: vars:

View File

@@ -38,4 +38,4 @@
vars: { volume: "{{ volume_information.stdout|from_json }}" } vars: { volume: "{{ volume_information.stdout|from_json }}" }
when: "volume.name == 'heketidbstorage'" when: "volume.name == 'heketidbstorage'"
- name: "Ensure heketi database volume exists." - name: "Ensure heketi database volume exists."
assert: { that: "heketi_database_volume_created is defined", msg: "Heketi database volume does not exist." } assert: { that: "heketi_database_volume_created is defined" , msg: "Heketi database volume does not exist." }

View File

@@ -6,7 +6,7 @@
- name: "Kubernetes Apps | Install and configure GlusterFS daemonset" - name: "Kubernetes Apps | Install and configure GlusterFS daemonset"
kube: kube:
name: "GlusterFS" name: "GlusterFS"
kubectl: "{{ bin_dir }}/kubectl" kubectl: "{{bin_dir}}/kubectl"
filename: "{{ kube_config_dir }}/glusterfs-daemonset.json" filename: "{{ kube_config_dir }}/glusterfs-daemonset.json"
state: "{{ rendering.changed | ternary('latest', 'present') }}" state: "{{ rendering.changed | ternary('latest', 'present') }}"
- name: "Kubernetes Apps | Label GlusterFS nodes" - name: "Kubernetes Apps | Label GlusterFS nodes"
@@ -33,6 +33,6 @@
- name: "Kubernetes Apps | Install and configure Heketi Service Account" - name: "Kubernetes Apps | Install and configure Heketi Service Account"
kube: kube:
name: "GlusterFS" name: "GlusterFS"
kubectl: "{{ bin_dir }}/kubectl" kubectl: "{{bin_dir}}/kubectl"
filename: "{{ kube_config_dir }}/heketi-service-account.json" filename: "{{ kube_config_dir }}/heketi-service-account.json"
state: "{{ rendering.changed | ternary('latest', 'present') }}" state: "{{ rendering.changed | ternary('latest', 'present') }}"

View File

@@ -1,19 +1,11 @@
--- ---
- name: Get storage nodes - register: "label_present"
register: "label_present"
command: "{{ bin_dir }}/kubectl get node --selector=storagenode=glusterfs,kubernetes.io/hostname={{ node }} --ignore-not-found=true" command: "{{ bin_dir }}/kubectl get node --selector=storagenode=glusterfs,kubernetes.io/hostname={{ node }} --ignore-not-found=true"
changed_when: false changed_when: false
- name: "Assign storage label" - name: "Assign storage label"
when: "label_present.stdout_lines|length == 0" when: "label_present.stdout_lines|length == 0"
command: "{{ bin_dir }}/kubectl label node {{ node }} storagenode=glusterfs" command: "{{ bin_dir }}/kubectl label node {{ node }} storagenode=glusterfs"
- register: "label_present"
- name: Get storage nodes again
register: "label_present"
command: "{{ bin_dir }}/kubectl get node --selector=storagenode=glusterfs,kubernetes.io/hostname={{ node }} --ignore-not-found=true" command: "{{ bin_dir }}/kubectl get node --selector=storagenode=glusterfs,kubernetes.io/hostname={{ node }} --ignore-not-found=true"
changed_when: false changed_when: false
- assert: { that: "label_present|length > 0", msg: "Node {{ node }} has not been assigned with label storagenode=glusterfs." }
- name: Ensure the label has been set
assert:
that: "label_present|length > 0"
msg: "Node {{ node }} has not been assigned with label storagenode=glusterfs."

View File

@@ -1,33 +1,26 @@
--- ---
- name: "Kubernetes Apps | Lay Down Heketi" - name: "Kubernetes Apps | Lay Down Heketi"
become: true become: true
template: template: { src: "heketi-deployment.json.j2", dest: "{{ kube_config_dir }}/heketi-deployment.json" }
src: "heketi-deployment.json.j2"
dest: "{{ kube_config_dir }}/heketi-deployment.json"
register: "rendering" register: "rendering"
- name: "Kubernetes Apps | Install and configure Heketi" - name: "Kubernetes Apps | Install and configure Heketi"
kube: kube:
name: "GlusterFS" name: "GlusterFS"
kubectl: "{{ bin_dir }}/kubectl" kubectl: "{{bin_dir}}/kubectl"
filename: "{{ kube_config_dir }}/heketi-deployment.json" filename: "{{ kube_config_dir }}/heketi-deployment.json"
state: "{{ rendering.changed | ternary('latest', 'present') }}" state: "{{ rendering.changed | ternary('latest', 'present') }}"
- name: "Ensure heketi is up and running." - name: "Ensure heketi is up and running."
changed_when: false changed_when: false
register: "heketi_state" register: "heketi_state"
vars: vars:
heketi_state: heketi_state: { stdout: "{}" }
stdout: "{}"
pods_query: "items[?kind=='Pod'].status.conditions|[0][?type=='Ready'].status|[0]" pods_query: "items[?kind=='Pod'].status.conditions|[0][?type=='Ready'].status|[0]"
deployments_query: "items[?kind=='Deployment'].status.conditions|[0][?type=='Available'].status|[0]" deployments_query: "items[?kind=='Deployment'].status.conditions|[0][?type=='Available'].status|[0]"
command: "{{ bin_dir }}/kubectl get deployments,pods --selector=glusterfs --output=json" command: "{{ bin_dir }}/kubectl get deployments,pods --selector=glusterfs --output=json"
until: until:
- "heketi_state.stdout|from_json|json_query(pods_query) == 'True'" - "heketi_state.stdout|from_json|json_query(pods_query) == 'True'"
- "heketi_state.stdout|from_json|json_query(deployments_query) == 'True'" - "heketi_state.stdout|from_json|json_query(deployments_query) == 'True'"
retries: 60 retries: 60
delay: 5 delay: 5
- set_fact:
- name: Set the Heketi pod name
set_fact:
heketi_pod_name: "{{ heketi_state.stdout|from_json|json_query(\"items[?kind=='Pod'].metadata.name|[0]\") }}" heketi_pod_name: "{{ heketi_state.stdout|from_json|json_query(\"items[?kind=='Pod'].metadata.name|[0]\") }}"

View File

@@ -7,7 +7,7 @@
- name: "Kubernetes Apps | Test Heketi" - name: "Kubernetes Apps | Test Heketi"
register: "heketi_service_state" register: "heketi_service_state"
command: "{{ bin_dir }}/kubectl get service heketi-storage-endpoints -o=name --ignore-not-found=true" command: "{{bin_dir}}/kubectl get service heketi-storage-endpoints -o=name --ignore-not-found=true"
changed_when: false changed_when: false
- name: "Kubernetes Apps | Bootstrap Heketi" - name: "Kubernetes Apps | Bootstrap Heketi"

View File

@@ -1,44 +1,27 @@
--- ---
- name: Get clusterrolebindings - register: "clusterrolebinding_state"
register: "clusterrolebinding_state" command: "{{bin_dir}}/kubectl get clusterrolebinding heketi-gluster-admin -o=name --ignore-not-found=true"
command: "{{ bin_dir }}/kubectl get clusterrolebinding heketi-gluster-admin -o=name --ignore-not-found=true"
changed_when: false changed_when: false
- name: "Kubernetes Apps | Deploy cluster role binding." - name: "Kubernetes Apps | Deploy cluster role binding."
when: "clusterrolebinding_state.stdout == \"\"" when: "clusterrolebinding_state.stdout == \"\""
command: "{{ bin_dir }}/kubectl create clusterrolebinding heketi-gluster-admin --clusterrole=edit --serviceaccount=default:heketi-service-account" command: "{{bin_dir}}/kubectl create clusterrolebinding heketi-gluster-admin --clusterrole=edit --serviceaccount=default:heketi-service-account"
- register: "clusterrolebinding_state"
- name: Get clusterrolebindings again command: "{{bin_dir}}/kubectl get clusterrolebinding heketi-gluster-admin -o=name --ignore-not-found=true"
register: "clusterrolebinding_state"
command: "{{ bin_dir }}/kubectl get clusterrolebinding heketi-gluster-admin -o=name --ignore-not-found=true"
changed_when: false changed_when: false
- assert: { that: "clusterrolebinding_state.stdout != \"\"", message: "Cluster role binding is not present." }
- name: Make sure that clusterrolebindings are present now - register: "secret_state"
assert: command: "{{bin_dir}}/kubectl get secret heketi-config-secret -o=name --ignore-not-found=true"
that: "clusterrolebinding_state.stdout != \"\""
msg: "Cluster role binding is not present."
- name: Get the heketi-config-secret secret
register: "secret_state"
command: "{{ bin_dir }}/kubectl get secret heketi-config-secret -o=name --ignore-not-found=true"
changed_when: false changed_when: false
- name: "Render Heketi secret configuration." - name: "Render Heketi secret configuration."
become: true become: true
template: template:
src: "heketi.json.j2" src: "heketi.json.j2"
dest: "{{ kube_config_dir }}/heketi.json" dest: "{{ kube_config_dir }}/heketi.json"
- name: "Deploy Heketi config secret" - name: "Deploy Heketi config secret"
when: "secret_state.stdout == \"\"" when: "secret_state.stdout == \"\""
command: "{{ bin_dir }}/kubectl create secret generic heketi-config-secret --from-file={{ kube_config_dir }}/heketi.json" command: "{{bin_dir}}/kubectl create secret generic heketi-config-secret --from-file={{ kube_config_dir }}/heketi.json"
- register: "secret_state"
- name: Get the heketi-config-secret secret again command: "{{bin_dir}}/kubectl get secret heketi-config-secret -o=name --ignore-not-found=true"
register: "secret_state"
command: "{{ bin_dir }}/kubectl get secret heketi-config-secret -o=name --ignore-not-found=true"
changed_when: false changed_when: false
- assert: { that: "secret_state.stdout != \"\"", message: "Heketi config secret is not present." }
- name: Make sure the heketi-config-secret secret exists now
assert:
that: "secret_state.stdout != \"\""
msg: "Heketi config secret is not present."

View File

@@ -7,6 +7,6 @@
- name: "Kubernetes Apps | Install and configure Heketi Storage" - name: "Kubernetes Apps | Install and configure Heketi Storage"
kube: kube:
name: "GlusterFS" name: "GlusterFS"
kubectl: "{{ bin_dir }}/kubectl" kubectl: "{{bin_dir}}/kubectl"
filename: "{{ kube_config_dir }}/heketi-storage.json" filename: "{{ kube_config_dir }}/heketi-storage.json"
state: "{{ rendering.changed | ternary('latest', 'present') }}" state: "{{ rendering.changed | ternary('latest', 'present') }}"

View File

@@ -8,7 +8,7 @@
register: "heketi_service" register: "heketi_service"
changed_when: false changed_when: false
- name: "Ensure heketi service is available." - name: "Ensure heketi service is available."
assert: { that: "heketi_service.stdout != \"\"" } assert: { that: "heketi_service.stdout != \"\"" }
- name: "Render storage class configuration." - name: "Render storage class configuration."
become: true become: true
vars: vars:
@@ -20,6 +20,6 @@
- name: "Kubernetes Apps | Install and configure Storace Class" - name: "Kubernetes Apps | Install and configure Storace Class"
kube: kube:
name: "GlusterFS" name: "GlusterFS"
kubectl: "{{ bin_dir }}/kubectl" kubectl: "{{bin_dir}}/kubectl"
filename: "{{ kube_config_dir }}/storageclass.yml" filename: "{{ kube_config_dir }}/storageclass.yml"
state: "{{ rendering.changed | ternary('latest', 'present') }}" state: "{{ rendering.changed | ternary('latest', 'present') }}"

View File

@@ -1,6 +1,6 @@
{ {
"kind": "DaemonSet", "kind": "DaemonSet",
"apiVersion": "apps/v1", "apiVersion": "extensions/v1beta1",
"metadata": { "metadata": {
"name": "glusterfs", "name": "glusterfs",
"labels": { "labels": {
@@ -12,11 +12,6 @@
} }
}, },
"spec": { "spec": {
"selector": {
"matchLabels": {
"glusterfs-node": "daemonset"
}
},
"template": { "template": {
"metadata": { "metadata": {
"name": "glusterfs", "name": "glusterfs",
@@ -74,7 +69,7 @@
}, },
"readinessProbe": { "readinessProbe": {
"timeoutSeconds": 3, "timeoutSeconds": 3,
"initialDelaySeconds": 3, "initialDelaySeconds": 60,
"exec": { "exec": {
"command": [ "command": [
"/bin/bash", "/bin/bash",
@@ -85,7 +80,7 @@
}, },
"livenessProbe": { "livenessProbe": {
"timeoutSeconds": 3, "timeoutSeconds": 3,
"initialDelaySeconds": 10, "initialDelaySeconds": 60,
"exec": { "exec": {
"command": [ "command": [
"/bin/bash", "/bin/bash",

View File

@@ -30,7 +30,7 @@
}, },
{ {
"kind": "Deployment", "kind": "Deployment",
"apiVersion": "apps/v1", "apiVersion": "extensions/v1beta1",
"metadata": { "metadata": {
"name": "deploy-heketi", "name": "deploy-heketi",
"labels": { "labels": {
@@ -42,11 +42,6 @@
} }
}, },
"spec": { "spec": {
"selector": {
"matchLabels": {
"name": "deploy-heketi"
}
},
"replicas": 1, "replicas": 1,
"template": { "template": {
"metadata": { "metadata": {
@@ -61,7 +56,7 @@
"serviceAccountName": "heketi-service-account", "serviceAccountName": "heketi-service-account",
"containers": [ "containers": [
{ {
"image": "heketi/heketi:9", "image": "heketi/heketi:7",
"imagePullPolicy": "Always", "imagePullPolicy": "Always",
"name": "deploy-heketi", "name": "deploy-heketi",
"env": [ "env": [
@@ -111,7 +106,7 @@
}, },
"livenessProbe": { "livenessProbe": {
"timeoutSeconds": 3, "timeoutSeconds": 3,
"initialDelaySeconds": 10, "initialDelaySeconds": 30,
"httpGet": { "httpGet": {
"path": "/hello", "path": "/hello",
"port": 8080 "port": 8080

View File

@@ -44,7 +44,7 @@
}, },
{ {
"kind": "Deployment", "kind": "Deployment",
"apiVersion": "apps/v1", "apiVersion": "extensions/v1beta1",
"metadata": { "metadata": {
"name": "heketi", "name": "heketi",
"labels": { "labels": {
@@ -55,11 +55,6 @@
} }
}, },
"spec": { "spec": {
"selector": {
"matchLabels": {
"name": "heketi"
}
},
"replicas": 1, "replicas": 1,
"template": { "template": {
"metadata": { "metadata": {
@@ -73,7 +68,7 @@
"serviceAccountName": "heketi-service-account", "serviceAccountName": "heketi-service-account",
"containers": [ "containers": [
{ {
"image": "heketi/heketi:9", "image": "heketi/heketi:7",
"imagePullPolicy": "Always", "imagePullPolicy": "Always",
"name": "heketi", "name": "heketi",
"env": [ "env": [
@@ -127,7 +122,7 @@
}, },
"livenessProbe": { "livenessProbe": {
"timeoutSeconds": 3, "timeoutSeconds": 3,
"initialDelaySeconds": 10, "initialDelaySeconds": 30,
"httpGet": { "httpGet": {
"path": "/hello", "path": "/hello",
"port": 8080 "port": 8080

View File

@@ -16,7 +16,7 @@
{ {
"addresses": [ "addresses": [
{ {
"ip": "{{ hostvars[node].ip }}" "ip": "{{ hostvars[node]['ansible_facts']['default_ipv4']['address'] }}"
} }
], ],
"ports": [ "ports": [

View File

@@ -12,7 +12,7 @@
"{{ node }}" "{{ node }}"
], ],
"storage": [ "storage": [
"{{ hostvars[node].ip }}" "{{ hostvars[node]['ansible_facts']['default_ipv4']['address'] }}"
] ]
}, },
"zone": 1 "zone": 1

View File

@@ -1,2 +0,0 @@
---
heketi_remove_lvm: false

View File

@@ -2,20 +2,18 @@
- name: "Install lvm utils (RedHat)" - name: "Install lvm utils (RedHat)"
become: true become: true
yum: yum:
name: "lvm2" name: "lvm2"
state: "present" state: "present"
when: "ansible_os_family == 'RedHat'" when: "ansible_os_family == 'RedHat'"
- name: "Install lvm utils (Debian)" - name: "Install lvm utils (Debian)"
become: true become: true
apt: apt:
name: "lvm2" name: "lvm2"
state: "present" state: "present"
when: "ansible_os_family == 'Debian'" when: "ansible_os_family == 'Debian'"
- name: "Get volume group information." - name: "Get volume group information."
environment:
PATH: "{{ ansible_env.PATH }}:/sbin" # Make sure we can workaround RH / CentOS conservative path management
become: true become: true
shell: "pvs {{ disk_volume_device_1 }} --option vg_name | tail -n+2" shell: "pvs {{ disk_volume_device_1 }} --option vg_name | tail -n+2"
register: "volume_groups" register: "volume_groups"
@@ -23,16 +21,12 @@
changed_when: false changed_when: false
- name: "Remove volume groups." - name: "Remove volume groups."
environment:
PATH: "{{ ansible_env.PATH }}:/sbin" # Make sure we can workaround RH / CentOS conservative path management
become: true become: true
command: "vgremove {{ volume_group }} --yes" command: "vgremove {{ volume_group }} --yes"
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." - name: "Remove physical volume from cluster disks."
environment:
PATH: "{{ ansible_env.PATH }}:/sbin" # Make sure we can workaround RH / CentOS conservative path management
become: true become: true
command: "pvremove {{ disk_volume_device_1 }} --yes" command: "pvremove {{ disk_volume_device_1 }} --yes"
ignore_errors: true ignore_errors: true
@@ -40,13 +34,13 @@
- name: "Remove lvm utils (RedHat)" - name: "Remove lvm utils (RedHat)"
become: true become: true
yum: yum:
name: "lvm2" name: "lvm2"
state: "absent" state: "absent"
when: "ansible_os_family == 'RedHat' and heketi_remove_lvm" when: "ansible_os_family == 'RedHat'"
- name: "Remove lvm utils (Debian)" - name: "Remove lvm utils (Debian)"
become: true become: true
apt: apt:
name: "lvm2" name: "lvm2"
state: "absent" state: "absent"
when: "ansible_os_family == 'Debian' and heketi_remove_lvm" when: "ansible_os_family == 'Debian'"

View File

@@ -1,5 +0,0 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- holmsten
- miouge1

View File

@@ -10,7 +10,7 @@ This project will create:
* AWS ELB in the Public Subnet for accessing the Kubernetes API from the internet * AWS ELB in the Public Subnet for accessing the Kubernetes API from the internet
**Requirements** **Requirements**
- Terraform 0.12.0 or newer - Terraform 0.8.7 or newer
**How to Use:** **How to Use:**

View File

@@ -1,11 +1,11 @@
terraform { terraform {
required_version = ">= 0.12.0" required_version = ">= 0.8.7"
} }
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" {}
@@ -16,32 +16,35 @@ 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_vpc_cidr_block = "${var.aws_vpc_cidr_block}"
aws_avail_zones="${slice(data.aws_availability_zones.available.names,0,2)}"
aws_cidr_subnets_private="${var.aws_cidr_subnets_private}"
aws_cidr_subnets_public="${var.aws_cidr_subnets_public}"
default_tags="${var.default_tags}"
aws_cluster_name = "${var.aws_cluster_name}"
aws_vpc_cidr_block = "${var.aws_vpc_cidr_block}"
aws_avail_zones = "${slice(data.aws_availability_zones.available.names, 0, 2)}"
aws_cidr_subnets_private = "${var.aws_cidr_subnets_private}"
aws_cidr_subnets_public = "${var.aws_cidr_subnets_public}"
default_tags = "${var.default_tags}"
} }
module "aws-elb" {
source = "./modules/elb"
aws_cluster_name = "${var.aws_cluster_name}" module "aws-elb" {
aws_vpc_id = "${module.aws-vpc.aws_vpc_id}" source = "modules/elb"
aws_avail_zones = "${slice(data.aws_availability_zones.available.names, 0, 2)}"
aws_subnet_ids_public = "${module.aws-vpc.aws_subnet_ids_public}" aws_cluster_name="${var.aws_cluster_name}"
aws_elb_api_port = "${var.aws_elb_api_port}" aws_vpc_id="${module.aws-vpc.aws_vpc_id}"
k8s_secure_api_port = "${var.k8s_secure_api_port}" aws_avail_zones="${slice(data.aws_availability_zones.available.names,0,2)}"
default_tags = "${var.default_tags}" aws_subnet_ids_public="${module.aws-vpc.aws_subnet_ids_public}"
aws_elb_api_port = "${var.aws_elb_api_port}"
k8s_secure_api_port = "${var.k8s_secure_api_port}"
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,122 +53,139 @@ 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}"
key_name = "${var.AWS_SSH_KEY_NAME}" vpc_security_group_ids = [ "${module.aws-vpc.aws_security_group}" ]
tags = "${merge(var.default_tags, map( key_name = "${var.AWS_SSH_KEY_NAME}"
"Name", "kubernetes-${var.aws_cluster_name}-bastion-${count.index}",
"Cluster", "${var.aws_cluster_name}", tags = "${merge(var.default_tags, map(
"Role", "bastion-${var.aws_cluster_name}-${count.index}" "Name", "kubernetes-${var.aws_cluster_name}-bastion-${count.index}",
))}" "Cluster", "${var.aws_cluster_name}",
"Role", "bastion-${var.aws_cluster_name}-${count.index}"
))}"
} }
/* /*
* Create K8s Master and worker nodes and etcd instances * Create K8s Master and worker nodes and etcd instances
* *
*/ */
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)}"
subnet_id = "${element(module.aws-vpc.aws_subnet_ids_private, count.index)}"
vpc_security_group_ids = "${module.aws-vpc.aws_security_group}" 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)}"
iam_instance_profile = "${module.aws-iam.kube-master-profile}"
key_name = "${var.AWS_SSH_KEY_NAME}"
tags = "${merge(var.default_tags, map( vpc_security_group_ids = [ "${module.aws-vpc.aws_security_group}" ]
"Name", "kubernetes-${var.aws_cluster_name}-master${count.index}",
"kubernetes.io/cluster/${var.aws_cluster_name}", "member",
"Role", "master" iam_instance_profile = "${module.aws-iam.kube-master-profile}"
))}" key_name = "${var.AWS_SSH_KEY_NAME}"
tags = "${merge(var.default_tags, map(
"Name", "kubernetes-${var.aws_cluster_name}-master${count.index}",
"kubernetes.io/cluster/${var.aws_cluster_name}", "member",
"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)}"
subnet_id = "${element(module.aws-vpc.aws_subnet_ids_private, count.index)}"
vpc_security_group_ids = "${module.aws-vpc.aws_security_group}" 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)}"
key_name = "${var.AWS_SSH_KEY_NAME}"
tags = "${merge(var.default_tags, map( vpc_security_group_ids = [ "${module.aws-vpc.aws_security_group}" ]
"Name", "kubernetes-${var.aws_cluster_name}-etcd${count.index}",
"kubernetes.io/cluster/${var.aws_cluster_name}", "member", key_name = "${var.AWS_SSH_KEY_NAME}"
"Role", "etcd"
))}" tags = "${merge(var.default_tags, map(
"Name", "kubernetes-${var.aws_cluster_name}-etcd${count.index}",
"kubernetes.io/cluster/${var.aws_cluster_name}", "member",
"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(
"Name", "kubernetes-${var.aws_cluster_name}-worker${count.index}",
"kubernetes.io/cluster/${var.aws_cluster_name}", "member",
"Role", "worker"
))}"
tags = "${merge(var.default_tags, map(
"Name", "kubernetes-${var.aws_cluster_name}-worker${count.index}",
"kubernetes.io/cluster/${var.aws_cluster_name}", "member",
"Role", "worker"
))}"
} }
/* /*
* Create Kubespray Inventory File * Create Kubespray Inventory File
* *
*/ */
data "template_file" "inventory" { data "template_file" "inventory" {
template = "${file("${path.module}/templates/inventory.tpl")}" template = "${file("${path.module}/templates/inventory.tpl")}"
vars {
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.*.tags.Name, aws_instance.k8s-master.*.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.*.tags.Name, aws_instance.k8s-etcd.*.private_ip))}"
list_master = "${join("\n",aws_instance.k8s-master.*.tags.Name)}"
list_node = "${join("\n",aws_instance.k8s-worker.*.tags.Name)}"
list_etcd = "${join("\n",aws_instance.k8s-etcd.*.tags.Name)}"
elb_api_fqdn = "apiserver_loadbalancer_domain_name=\"${module.aws-elb.aws_elb_api_fqdn}\""
}
vars = {
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_node = "${join("\n", formatlist("%s ansible_host=%s", aws_instance.k8s-worker.*.private_dns, 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))}"
list_master = "${join("\n", aws_instance.k8s-master.*.private_dns)}"
list_node = "${join("\n", aws_instance.k8s-worker.*.private_dns)}"
list_etcd = "${join("\n", aws_instance.k8s-etcd.*.private_dns)}"
elb_api_fqdn = "apiserver_loadbalancer_domain_name=\"${module.aws-elb.aws_elb_api_fqdn}\""
}
} }
resource "null_resource" "inventories" { resource "null_resource" "inventories" {
provisioner "local-exec" { provisioner "local-exec" {
command = "echo '${data.template_file.inventory.rendered}' > ${var.inventory_file}" command = "echo '${data.template_file.inventory.rendered}' > ${var.inventory_file}"
} }
triggers = { triggers {
template = "${data.template_file.inventory.rendered}" template = "${data.template_file.inventory.rendered}"
} }
} }

View File

@@ -1,54 +1,55 @@
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" {
type = "egress" type = "egress"
from_port = 0 from_port = 0
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"
} }
health_check { health_check {
healthy_threshold = 2 healthy_threshold = 2
unhealthy_threshold = 2 unhealthy_threshold = 2
timeout = 3 timeout = 3
target = "TCP:${var.k8s_secure_api_port}" target = "TCP:${var.k8s_secure_api_port}"
interval = 30 interval = 30
} }
cross_zone_load_balancing = true cross_zone_load_balancing = true
idle_timeout = 400 idle_timeout = 400
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(

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

@@ -1,30 +1,33 @@
variable "aws_cluster_name" { variable "aws_cluster_name" {
description = "Name of Cluster" description = "Name of Cluster"
} }
variable "aws_vpc_id" { variable "aws_vpc_id" {
description = "AWS VPC ID" description = "AWS VPC ID"
} }
variable "aws_elb_api_port" { variable "aws_elb_api_port" {
description = "Port for AWS ELB" description = "Port for AWS ELB"
} }
variable "k8s_secure_api_port" { variable "k8s_secure_api_port" {
description = "Secure Port of K8S API Server" description = "Secure Port of K8S API Server"
} }
variable "aws_avail_zones" { variable "aws_avail_zones" {
description = "Availability Zones Used" description = "Availability Zones Used"
type = "list" type = "list"
} }
variable "aws_subnet_ids_public" { variable "aws_subnet_ids_public" {
description = "IDs of Public Subnets" description = "IDs of Public Subnets"
type = "list" type = "list"
} }
variable "default_tags" { variable "default_tags" {
description = "Tags for all resources" description = "Tags for all resources"
type = "map" type = "map"
} }

View File

@@ -1,9 +1,8 @@
#Add AWS Roles for Kubernetes #Add AWS Roles for Kubernetes
resource "aws_iam_role" "kube-master" { resource "aws_iam_role" "kube-master" {
name = "kubernetes-${var.aws_cluster_name}-master" name = "kubernetes-${var.aws_cluster_name}-master"
assume_role_policy = <<EOF
assume_role_policy = <<EOF
{ {
"Version": "2012-10-17", "Version": "2012-10-17",
"Statement": [ "Statement": [
@@ -20,9 +19,8 @@ EOF
} }
resource "aws_iam_role" "kube-worker" { resource "aws_iam_role" "kube-worker" {
name = "kubernetes-${var.aws_cluster_name}-node" name = "kubernetes-${var.aws_cluster_name}-node"
assume_role_policy = <<EOF
assume_role_policy = <<EOF
{ {
"Version": "2012-10-17", "Version": "2012-10-17",
"Statement": [ "Statement": [
@@ -41,10 +39,9 @@ EOF
#Add AWS Policies for Kubernetes #Add AWS Policies for Kubernetes
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
{ {
"Version": "2012-10-17", "Version": "2012-10-17",
"Statement": [ "Statement": [
@@ -76,10 +73,9 @@ 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
{ {
"Version": "2012-10-17", "Version": "2012-10-17",
"Statement": [ "Statement": [
@@ -128,14 +124,15 @@ resource "aws_iam_role_policy" "kube-worker" {
EOF EOF
} }
#Create AWS Instance Profiles #Create AWS Instance Profiles
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,3 +1,3 @@
variable "aws_cluster_name" { variable "aws_cluster_name" {
description = "Name of Cluster" description = "Name of Cluster"
} }

View File

@@ -1,55 +1,60 @@
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,78 +62,81 @@ 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 {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.cluster-vpc-internetgw.id}"
}
route { tags = "${merge(var.default_tags, map(
cidr_block = "0.0.0.0/0" "Name", "kubernetes-${var.aws_cluster_name}-routetable-public"
gateway_id = "${aws_internet_gateway.cluster-vpc-internetgw.id}" ))}"
}
tags = "${merge(var.default_tags, map(
"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 {
cidr_block = "0.0.0.0/0"
nat_gateway_id = "${element(aws_nat_gateway.cluster-nat-gateway.*.id, count.index)}"
}
route { tags = "${merge(var.default_tags, map(
cidr_block = "0.0.0.0/0" "Name", "kubernetes-${var.aws_cluster_name}-routetable-private-${count.index}"
nat_gateway_id = "${element(aws_nat_gateway.cluster-nat-gateway.*.id, count.index)}" ))}"
}
tags = "${merge(var.default_tags, map(
"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" {
type = "ingress" type = "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" {
type = "egress" type = "egress"
from_port = 0 from_port = 0
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" {
type = "ingress" type = "ingress"
from_port = 22 from_port = 22
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,19 +1,21 @@
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" {
value = aws_subnet.cluster-vpc-subnets-private.*.id value = ["${aws_subnet.cluster-vpc-subnets-private.*.id}"]
} }
output "aws_subnet_ids_public" { output "aws_subnet_ids_public" {
value = aws_subnet.cluster-vpc-subnets-public.*.id value = ["${aws_subnet.cluster-vpc-subnets-public.*.id}"]
} }
output "aws_security_group" { output "aws_security_group" {
value = aws_security_group.kubernetes.*.id value = ["${aws_security_group.kubernetes.*.id}"]
} }
output "default_tags" { output "default_tags" {
value = "${var.default_tags}" value = "${var.default_tags}"
} }

View File

@@ -1,27 +1,29 @@
variable "aws_vpc_cidr_block" { variable "aws_vpc_cidr_block" {
description = "CIDR Blocks for AWS VPC" description = "CIDR Blocks for AWS VPC"
} }
variable "aws_cluster_name" { variable "aws_cluster_name" {
description = "Name of Cluster" description = "Name of Cluster"
} }
variable "aws_avail_zones" { variable "aws_avail_zones" {
description = "AWS Availability Zones Used" description = "AWS Availability Zones Used"
type = "list" 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" 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" type = "list"
} }
variable "default_tags" { variable "default_tags" {
description = "Default tags for all resources" description = "Default tags for all resources"
type = "map" type = "map"
} }

View File

@@ -1,27 +1,28 @@
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" {
value = "${module.aws-elb.aws_elb_api_fqdn}:${var.aws_elb_api_port}" value = "${module.aws-elb.aws_elb_api_fqdn}:${var.aws_elb_api_port}"
} }
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

@@ -1,53 +0,0 @@
#Global Vars
aws_cluster_name = "devtest"
#VPC Vars
aws_vpc_cidr_block = "10.250.192.0/18"
aws_cidr_subnets_private = ["10.250.192.0/20", "10.250.208.0/20"]
aws_cidr_subnets_public = ["10.250.224.0/20", "10.250.240.0/20"]
#Bastion Host
aws_bastion_size = "t2.medium"
#Kubernetes Cluster
aws_kube_master_num = 3
aws_kube_master_size = "t2.medium"
aws_etcd_num = 3
aws_etcd_size = "t2.medium"
aws_kube_worker_num = 4
aws_kube_worker_size = "t2.medium"
#Settings AWS ELB
aws_elb_api_port = 6443
k8s_secure_api_port = 6443
kube_insecure_apiserver_address = "0.0.0.0"
default_tags = {
# Env = "devtest" # Product = "kubernetes"
}
inventory_file = "../../../inventory/hosts"
## Credentials
#AWS Access Key
AWS_ACCESS_KEY_ID = ""
#AWS Secret Key
AWS_SECRET_ACCESS_KEY = ""
#EC2 SSH Key Name
AWS_SSH_KEY_NAME = ""
#AWS Region
AWS_DEFAULT_REGION = "eu-central-1"

View File

@@ -1 +0,0 @@
../../../../inventory/sample/group_vars

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