Compare commits
No commits in common. "master" and "1.5.0" have entirely different histories.
1487 changed files with 25035 additions and 85409 deletions
|
@ -1,30 +0,0 @@
|
||||||
---
|
|
||||||
parseable: true
|
|
||||||
skip_list:
|
|
||||||
# see https://docs.ansible.com/ansible-lint/rules/default_rules.html for a list of all default rules
|
|
||||||
|
|
||||||
# DO NOT add any other rules to this skip_list, instead use local `# noqa` with a comment explaining WHY it is necessary
|
|
||||||
|
|
||||||
# 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'
|
|
||||||
|
|
||||||
# [role-name] "meta/main.yml" Role name role-name does not match ``^+$`` pattern
|
|
||||||
# Meta roles in Kubespray don't need proper names
|
|
||||||
# (Disabled in June 2021)
|
|
||||||
- 'role-name'
|
|
||||||
|
|
||||||
# [var-naming] "defaults/main.yml" File defines variable 'apiVersion' that violates variable naming standards
|
|
||||||
# In Kubespray we use variables that use camelCase to match their k8s counterparts
|
|
||||||
# (Disabled in June 2021)
|
|
||||||
- 'var-naming'
|
|
|
@ -1,15 +0,0 @@
|
||||||
root = true
|
|
||||||
|
|
||||||
[*.{yaml,yml,yml.j2,yaml.j2}]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
||||||
charset = utf-8
|
|
||||||
|
|
||||||
[{Dockerfile}]
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
||||||
charset = utf-8
|
|
44
.github/ISSUE_TEMPLATE/bug-report.md
vendored
44
.github/ISSUE_TEMPLATE/bug-report.md
vendored
|
@ -1,44 +0,0 @@
|
||||||
---
|
|
||||||
name: Bug Report
|
|
||||||
about: Report a bug encountered while operating Kubernetes
|
|
||||||
labels: kind/bug
|
|
||||||
|
|
||||||
---
|
|
||||||
<!--
|
|
||||||
Please, 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
|
|
||||||
might close your issue. If we're wrong, PLEASE feel free to reopen it and
|
|
||||||
explain why.
|
|
||||||
-->
|
|
||||||
|
|
||||||
**Environment**:
|
|
||||||
- **Cloud provider or hardware configuration:**
|
|
||||||
|
|
||||||
- **OS (`printf "$(uname -srm)\n$(cat /etc/os-release)\n"`):**
|
|
||||||
|
|
||||||
- **Version of Ansible** (`ansible --version`):
|
|
||||||
|
|
||||||
- **Version of Python** (`python --version`):
|
|
||||||
|
|
||||||
|
|
||||||
**Kubespray version (commit) (`git rev-parse --short HEAD`):**
|
|
||||||
|
|
||||||
|
|
||||||
**Network plugin used**:
|
|
||||||
|
|
||||||
|
|
||||||
**Full inventory with variables (`ansible -i inventory/sample/inventory.ini all -m debug -a "var=hostvars[inventory_hostname]"`):**
|
|
||||||
<!-- We recommend using snippets services like https://gist.github.com/ etc. -->
|
|
||||||
|
|
||||||
**Command used to invoke ansible**:
|
|
||||||
|
|
||||||
|
|
||||||
**Output of ansible run**:
|
|
||||||
<!-- We recommend using snippets services like https://gist.github.com/ etc. -->
|
|
||||||
|
|
||||||
**Anything else do we need to know**:
|
|
||||||
<!-- By running scripts/collect-info.yaml you can get a lot of useful informations.
|
|
||||||
Script can be started by:
|
|
||||||
ansible-playbook -i <inventory_file_path> -u <ssh_user> -e ansible_ssh_user=<ssh_user> -b --become-user=root -e dir=`pwd` scripts/collect-info.yaml
|
|
||||||
(If you using CoreOS remember to add '-e ansible_python_interpreter=/opt/bin/python').
|
|
||||||
After running this command you can find logs in `pwd`/logs.tar.gz. You can even upload somewhere entire file and paste link here.-->
|
|
11
.github/ISSUE_TEMPLATE/enhancement.md
vendored
11
.github/ISSUE_TEMPLATE/enhancement.md
vendored
|
@ -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**:
|
|
20
.github/ISSUE_TEMPLATE/failing-test.md
vendored
20
.github/ISSUE_TEMPLATE/failing-test.md
vendored
|
@ -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**:
|
|
18
.github/ISSUE_TEMPLATE/support.md
vendored
18
.github/ISSUE_TEMPLATE/support.md
vendored
|
@ -1,18 +0,0 @@
|
||||||
---
|
|
||||||
name: Support Request
|
|
||||||
about: Support request or question relating to Kubespray
|
|
||||||
labels: kind/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/.
|
|
||||||
-->
|
|
44
.github/PULL_REQUEST_TEMPLATE.md
vendored
44
.github/PULL_REQUEST_TEMPLATE.md
vendored
|
@ -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
|
|
||||||
|
|
||||||
```
|
|
117
.gitignore
vendored
117
.gitignore
vendored
|
@ -1,117 +0,0 @@
|
||||||
.vagrant
|
|
||||||
*.retry
|
|
||||||
**/vagrant_ansible_inventory
|
|
||||||
*.iml
|
|
||||||
temp
|
|
||||||
contrib/offline/offline-files
|
|
||||||
contrib/offline/offline-files.tar.gz
|
|
||||||
.idea
|
|
||||||
.vscode
|
|
||||||
.tox
|
|
||||||
.cache
|
|
||||||
*.bak
|
|
||||||
*.tfstate
|
|
||||||
*.tfstate.backup
|
|
||||||
.terraform/
|
|
||||||
contrib/terraform/aws/credentials.tfvars
|
|
||||||
.terraform.lock.hcl
|
|
||||||
/ssh-bastion.conf
|
|
||||||
**/*.sw[pon]
|
|
||||||
*~
|
|
||||||
vagrant/
|
|
||||||
plugins/mitogen
|
|
||||||
deploy.sh
|
|
||||||
|
|
||||||
# Ansible inventory
|
|
||||||
inventory/*
|
|
||||||
!inventory/local
|
|
||||||
!inventory/sample
|
|
||||||
!inventory/c12s-sample
|
|
||||||
inventory/*/artifacts/
|
|
||||||
|
|
||||||
# Byte-compiled / optimized / DLL files
|
|
||||||
__pycache__/
|
|
||||||
*.py[cod]
|
|
||||||
*$py.class
|
|
||||||
|
|
||||||
# Distribution / packaging
|
|
||||||
.Python
|
|
||||||
env/
|
|
||||||
build/
|
|
||||||
credentials/
|
|
||||||
develop-eggs/
|
|
||||||
dist/
|
|
||||||
downloads/
|
|
||||||
eggs/
|
|
||||||
.eggs/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
*.egg-info/
|
|
||||||
.installed.cfg
|
|
||||||
*.egg
|
|
||||||
|
|
||||||
# PyInstaller
|
|
||||||
# Usually these files are written by a python script from a template
|
|
||||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
||||||
*.manifest
|
|
||||||
*.spec
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
pip-delete-this-directory.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
htmlcov/
|
|
||||||
.tox/
|
|
||||||
.coverage
|
|
||||||
.coverage.*
|
|
||||||
.cache
|
|
||||||
nosetests.xml
|
|
||||||
coverage.xml
|
|
||||||
*,cover
|
|
||||||
.hypothesis/
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
*.pot
|
|
||||||
|
|
||||||
# Django stuff:
|
|
||||||
*.log
|
|
||||||
local_settings.py
|
|
||||||
|
|
||||||
# Flask stuff:
|
|
||||||
instance/
|
|
||||||
.webassets-cache
|
|
||||||
|
|
||||||
# Scrapy stuff:
|
|
||||||
.scrapy
|
|
||||||
|
|
||||||
# Sphinx documentation
|
|
||||||
docs/_build/
|
|
||||||
|
|
||||||
# PyBuilder
|
|
||||||
target/
|
|
||||||
|
|
||||||
# IPython Notebook
|
|
||||||
.ipynb_checkpoints
|
|
||||||
|
|
||||||
# pyenv
|
|
||||||
.python-version
|
|
||||||
|
|
||||||
# dotenv
|
|
||||||
.env
|
|
||||||
|
|
||||||
# virtualenv
|
|
||||||
venv/
|
|
||||||
ENV/
|
|
||||||
|
|
||||||
# molecule
|
|
||||||
roles/**/molecule/**/__pycache__/
|
|
||||||
|
|
||||||
# macOS
|
|
||||||
.DS_Store
|
|
||||||
|
|
||||||
# Temp location used by our scripts
|
|
||||||
scripts/tmp/
|
|
||||||
tmp.md
|
|
|
@ -1,84 +0,0 @@
|
||||||
---
|
|
||||||
stages:
|
|
||||||
- unit-tests
|
|
||||||
- deploy-part1
|
|
||||||
- moderator
|
|
||||||
- deploy-part2
|
|
||||||
- deploy-part3
|
|
||||||
- deploy-special
|
|
||||||
|
|
||||||
variables:
|
|
||||||
KUBESPRAY_VERSION: v2.20.0
|
|
||||||
FAILFASTCI_NAMESPACE: 'kargo-ci'
|
|
||||||
GITLAB_REPOSITORY: 'kargo-ci/kubernetes-sigs-kubespray'
|
|
||||||
ANSIBLE_FORCE_COLOR: "true"
|
|
||||||
MAGIC: "ci check this"
|
|
||||||
TEST_ID: "$CI_PIPELINE_ID-$CI_BUILD_ID"
|
|
||||||
CI_TEST_VARS: "./tests/files/${CI_JOB_NAME}.yml"
|
|
||||||
CI_TEST_REGISTRY_MIRROR: "./tests/common/_docker_hub_registry_mirror.yml"
|
|
||||||
CI_TEST_SETTING: "./tests/common/_kubespray_test_settings.yml"
|
|
||||||
GS_ACCESS_KEY_ID: $GS_KEY
|
|
||||||
GS_SECRET_ACCESS_KEY: $GS_SECRET
|
|
||||||
CONTAINER_ENGINE: docker
|
|
||||||
SSH_USER: root
|
|
||||||
GCE_PREEMPTIBLE: "false"
|
|
||||||
ANSIBLE_KEEP_REMOTE_FILES: "1"
|
|
||||||
ANSIBLE_CONFIG: ./tests/ansible.cfg
|
|
||||||
ANSIBLE_INVENTORY: ./inventory/sample/${CI_JOB_NAME}-${BUILD_NUMBER}.ini
|
|
||||||
IDEMPOT_CHECK: "false"
|
|
||||||
RESET_CHECK: "false"
|
|
||||||
REMOVE_NODE_CHECK: "false"
|
|
||||||
UPGRADE_TEST: "false"
|
|
||||||
MITOGEN_ENABLE: "false"
|
|
||||||
ANSIBLE_LOG_LEVEL: "-vv"
|
|
||||||
RECOVER_CONTROL_PLANE_TEST: "false"
|
|
||||||
RECOVER_CONTROL_PLANE_TEST_GROUPS: "etcd[2:],kube_control_plane[1:]"
|
|
||||||
TERRAFORM_VERSION: 1.0.8
|
|
||||||
ANSIBLE_MAJOR_VERSION: "2.11"
|
|
||||||
|
|
||||||
before_script:
|
|
||||||
- ./tests/scripts/rebase.sh
|
|
||||||
- update-alternatives --install /usr/bin/python python /usr/bin/python3 1
|
|
||||||
- python -m pip uninstall -y ansible ansible-base ansible-core
|
|
||||||
- python -m pip install -r tests/requirements-${ANSIBLE_MAJOR_VERSION}.txt
|
|
||||||
- mkdir -p /.ssh
|
|
||||||
|
|
||||||
.job: &job
|
|
||||||
tags:
|
|
||||||
- packet
|
|
||||||
image: quay.io/kubespray/kubespray:$KUBESPRAY_VERSION
|
|
||||||
artifacts:
|
|
||||||
when: always
|
|
||||||
paths:
|
|
||||||
- cluster-dump/
|
|
||||||
|
|
||||||
.testcases: &testcases
|
|
||||||
<<: *job
|
|
||||||
retry: 1
|
|
||||||
before_script:
|
|
||||||
- update-alternatives --install /usr/bin/python python /usr/bin/python3 1
|
|
||||||
- ./tests/scripts/rebase.sh
|
|
||||||
- ./tests/scripts/testcases_prepare.sh
|
|
||||||
script:
|
|
||||||
- ./tests/scripts/testcases_run.sh
|
|
||||||
after_script:
|
|
||||||
- chronic ./tests/scripts/testcases_cleanup.sh
|
|
||||||
|
|
||||||
# For failfast, at least 1 job must be defined in .gitlab-ci.yml
|
|
||||||
# Premoderated with manual actions
|
|
||||||
ci-authorized:
|
|
||||||
extends: .job
|
|
||||||
stage: moderator
|
|
||||||
script:
|
|
||||||
- /bin/sh scripts/premoderator.sh
|
|
||||||
except: ['triggers', 'master']
|
|
||||||
# Disable ci moderator
|
|
||||||
only: []
|
|
||||||
|
|
||||||
include:
|
|
||||||
- .gitlab-ci/lint.yml
|
|
||||||
- .gitlab-ci/shellcheck.yml
|
|
||||||
- .gitlab-ci/terraform.yml
|
|
||||||
- .gitlab-ci/packet.yml
|
|
||||||
- .gitlab-ci/vagrant.yml
|
|
||||||
- .gitlab-ci/molecule.yml
|
|
|
@ -1,90 +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.19
|
|
||||||
script:
|
|
||||||
- ./tests/scripts/vagrant-validate.sh
|
|
||||||
except: ['triggers', 'master']
|
|
||||||
|
|
||||||
ansible-lint:
|
|
||||||
extends: .job
|
|
||||||
stage: unit-tests
|
|
||||||
tags: [light]
|
|
||||||
script:
|
|
||||||
- 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 uninstall -y ansible ansible-base ansible-core
|
|
||||||
- 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@0.22.0
|
|
||||||
script:
|
|
||||||
- markdownlint $(find . -name '*.md' | grep -vF './.git') --ignore docs/_sidebar.md --ignore contrib/dind/README.md
|
|
||||||
|
|
||||||
check-readme-versions:
|
|
||||||
stage: unit-tests
|
|
||||||
tags: [light]
|
|
||||||
image: python:3
|
|
||||||
script:
|
|
||||||
- tests/scripts/check_readme_versions.sh
|
|
||||||
|
|
||||||
check-typo:
|
|
||||||
stage: unit-tests
|
|
||||||
tags: [light]
|
|
||||||
image: python:3
|
|
||||||
script:
|
|
||||||
- tests/scripts/check_typo.sh
|
|
||||||
|
|
||||||
ci-matrix:
|
|
||||||
stage: unit-tests
|
|
||||||
tags: [light]
|
|
||||||
image: python:3
|
|
||||||
script:
|
|
||||||
- tests/scripts/md-table/test.sh
|
|
|
@ -1,86 +0,0 @@
|
||||||
---
|
|
||||||
|
|
||||||
.molecule:
|
|
||||||
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 uninstall -y ansible ansible-base ansible-core
|
|
||||||
- python -m pip install -r tests/requirements.txt
|
|
||||||
- ./tests/scripts/vagrant_clean.sh
|
|
||||||
script:
|
|
||||||
- ./tests/scripts/molecule_run.sh
|
|
||||||
after_script:
|
|
||||||
- chronic ./tests/scripts/molecule_logs.sh
|
|
||||||
artifacts:
|
|
||||||
when: always
|
|
||||||
paths:
|
|
||||||
- molecule_logs/
|
|
||||||
|
|
||||||
# CI template for periodic CI jobs
|
|
||||||
# Enabled when PERIODIC_CI_ENABLED var is set
|
|
||||||
.molecule_periodic:
|
|
||||||
only:
|
|
||||||
variables:
|
|
||||||
- $PERIODIC_CI_ENABLED
|
|
||||||
allow_failure: true
|
|
||||||
extends: .molecule
|
|
||||||
|
|
||||||
molecule_full:
|
|
||||||
extends: .molecule_periodic
|
|
||||||
|
|
||||||
molecule_no_container_engines:
|
|
||||||
extends: .molecule
|
|
||||||
script:
|
|
||||||
- ./tests/scripts/molecule_run.sh -e container-engine
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
molecule_docker:
|
|
||||||
extends: .molecule
|
|
||||||
script:
|
|
||||||
- ./tests/scripts/molecule_run.sh -i container-engine/cri-dockerd
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
molecule_containerd:
|
|
||||||
extends: .molecule
|
|
||||||
script:
|
|
||||||
- ./tests/scripts/molecule_run.sh -i container-engine/containerd
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
molecule_cri-o:
|
|
||||||
extends: .molecule
|
|
||||||
stage: deploy-part2
|
|
||||||
script:
|
|
||||||
- ./tests/scripts/molecule_run.sh -i container-engine/cri-o
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
# Stage 3 container engines don't get as much attention so allow them to fail
|
|
||||||
molecule_kata:
|
|
||||||
extends: .molecule
|
|
||||||
stage: deploy-part3
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- ./tests/scripts/molecule_run.sh -i container-engine/kata-containers
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
molecule_gvisor:
|
|
||||||
extends: .molecule
|
|
||||||
stage: deploy-part3
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- ./tests/scripts/molecule_run.sh -i container-engine/gvisor
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
molecule_youki:
|
|
||||||
extends: .molecule
|
|
||||||
stage: deploy-part3
|
|
||||||
allow_failure: true
|
|
||||||
script:
|
|
||||||
- ./tests/scripts/molecule_run.sh -i container-engine/youki
|
|
||||||
when: on_success
|
|
|
@ -1,328 +0,0 @@
|
||||||
---
|
|
||||||
.packet:
|
|
||||||
extends: .testcases
|
|
||||||
variables:
|
|
||||||
ANSIBLE_TIMEOUT: "120"
|
|
||||||
CI_PLATFORM: packet
|
|
||||||
SSH_USER: kubespray
|
|
||||||
tags:
|
|
||||||
- packet
|
|
||||||
except: [triggers]
|
|
||||||
|
|
||||||
# CI template for PRs
|
|
||||||
.packet_pr:
|
|
||||||
only: [/^pr-.*$/]
|
|
||||||
extends: .packet
|
|
||||||
|
|
||||||
# CI template for periodic CI jobs
|
|
||||||
# Enabled when PERIODIC_CI_ENABLED var is set
|
|
||||||
.packet_periodic:
|
|
||||||
only:
|
|
||||||
variables:
|
|
||||||
- $PERIODIC_CI_ENABLED
|
|
||||||
allow_failure: true
|
|
||||||
extends: .packet
|
|
||||||
|
|
||||||
# The ubuntu20-calico-aio jobs are meant as early stages to prevent running the full CI if something is horribly broken
|
|
||||||
packet_ubuntu20-calico-aio:
|
|
||||||
stage: deploy-part1
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
variables:
|
|
||||||
RESET_CHECK: "true"
|
|
||||||
|
|
||||||
packet_ubuntu20-calico-aio-ansible-2_11:
|
|
||||||
stage: deploy-part1
|
|
||||||
extends: .packet_periodic
|
|
||||||
when: on_success
|
|
||||||
variables:
|
|
||||||
ANSIBLE_MAJOR_VERSION: "2.11"
|
|
||||||
RESET_CHECK: "true"
|
|
||||||
|
|
||||||
# ### PR JOBS PART2
|
|
||||||
|
|
||||||
packet_ubuntu18-aio-docker:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_ubuntu20-aio-docker:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_ubuntu20-calico-aio-hardening:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_ubuntu18-calico-aio:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_ubuntu22-aio-docker:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_ubuntu22-calico-aio:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_centos7-flannel-addons-ha:
|
|
||||||
extends: .packet_pr
|
|
||||||
stage: deploy-part2
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_almalinux8-crio:
|
|
||||||
extends: .packet_pr
|
|
||||||
stage: deploy-part2
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_ubuntu18-crio:
|
|
||||||
extends: .packet_pr
|
|
||||||
stage: deploy-part2
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
packet_fedora35-crio:
|
|
||||||
extends: .packet_pr
|
|
||||||
stage: deploy-part2
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
packet_ubuntu16-canal-ha:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_periodic
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_ubuntu16-canal-sep:
|
|
||||||
stage: deploy-special
|
|
||||||
extends: .packet_pr
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
packet_ubuntu16-flannel-ha:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
packet_debian10-cilium-svc-proxy:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_periodic
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_debian10-calico:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_debian10-docker:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_debian11-calico:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_debian11-docker:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_centos7-calico-ha-once-localhost:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
variables:
|
|
||||||
# This will instruct Docker not to start over TLS.
|
|
||||||
DOCKER_TLS_CERTDIR: ""
|
|
||||||
services:
|
|
||||||
- docker:19.03.9-dind
|
|
||||||
|
|
||||||
packet_almalinux8-kube-ovn:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_periodic
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_almalinux8-calico:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_rockylinux8-calico:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_rockylinux9-calico:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_almalinux8-docker:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_fedora36-docker-weave:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_opensuse-canal:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_periodic
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_opensuse-docker-cilium:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
# ### MANUAL JOBS
|
|
||||||
|
|
||||||
packet_ubuntu16-docker-weave-sep:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
packet_ubuntu18-cilium-sep:
|
|
||||||
stage: deploy-special
|
|
||||||
extends: .packet_pr
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
packet_ubuntu18-flannel-ha:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
packet_ubuntu18-flannel-ha-once:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
# Calico HA eBPF
|
|
||||||
packet_almalinux8-calico-ha-ebpf:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
packet_debian9-macvlan:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
packet_centos7-calico-ha:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
packet_centos7-multus-calico:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
packet_centos7-canal-ha:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
packet_fedora36-docker-calico:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_periodic
|
|
||||||
when: on_success
|
|
||||||
variables:
|
|
||||||
RESET_CHECK: "true"
|
|
||||||
|
|
||||||
packet_fedora35-calico-selinux:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_periodic
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_fedora35-calico-swap-selinux:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
packet_amazon-linux-2-aio:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
packet_almalinux8-calico-nodelocaldns-secondary:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
packet_fedora36-kube-ovn:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_periodic
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
# ### PR JOBS PART3
|
|
||||||
# Long jobs (45min+)
|
|
||||||
|
|
||||||
packet_centos7-weave-upgrade-ha:
|
|
||||||
stage: deploy-part3
|
|
||||||
extends: .packet_periodic
|
|
||||||
when: on_success
|
|
||||||
variables:
|
|
||||||
UPGRADE_TEST: basic
|
|
||||||
|
|
||||||
packet_ubuntu20-calico-etcd-kubeadm-upgrade-ha:
|
|
||||||
stage: deploy-part3
|
|
||||||
extends: .packet_periodic
|
|
||||||
when: on_success
|
|
||||||
variables:
|
|
||||||
UPGRADE_TEST: basic
|
|
||||||
|
|
||||||
# Calico HA Wireguard
|
|
||||||
packet_ubuntu20-calico-ha-wireguard:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .packet_pr
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
packet_debian11-calico-upgrade:
|
|
||||||
stage: deploy-part3
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
variables:
|
|
||||||
UPGRADE_TEST: graceful
|
|
||||||
|
|
||||||
packet_almalinux8-calico-remove-node:
|
|
||||||
stage: deploy-part3
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
variables:
|
|
||||||
REMOVE_NODE_CHECK: "true"
|
|
||||||
REMOVE_NODE_NAME: "instance-3"
|
|
||||||
|
|
||||||
packet_ubuntu20-calico-etcd-kubeadm:
|
|
||||||
stage: deploy-part3
|
|
||||||
extends: .packet_pr
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
packet_debian11-calico-upgrade-once:
|
|
||||||
stage: deploy-part3
|
|
||||||
extends: .packet_periodic
|
|
||||||
when: on_success
|
|
||||||
variables:
|
|
||||||
UPGRADE_TEST: graceful
|
|
||||||
|
|
||||||
packet_ubuntu18-calico-ha-recover:
|
|
||||||
stage: deploy-part3
|
|
||||||
extends: .packet_periodic
|
|
||||||
when: on_success
|
|
||||||
variables:
|
|
||||||
RECOVER_CONTROL_PLANE_TEST: "true"
|
|
||||||
RECOVER_CONTROL_PLANE_TEST_GROUPS: "etcd[2:],kube_control_plane[1:]"
|
|
||||||
|
|
||||||
packet_ubuntu18-calico-ha-recover-noquorum:
|
|
||||||
stage: deploy-part3
|
|
||||||
extends: .packet_periodic
|
|
||||||
when: on_success
|
|
||||||
variables:
|
|
||||||
RECOVER_CONTROL_PLANE_TEST: "true"
|
|
||||||
RECOVER_CONTROL_PLANE_TEST_GROUPS: "etcd[1:],kube_control_plane[1:]"
|
|
|
@ -1,16 +0,0 @@
|
||||||
---
|
|
||||||
shellcheck:
|
|
||||||
extends: .job
|
|
||||||
stage: unit-tests
|
|
||||||
tags: [light]
|
|
||||||
variables:
|
|
||||||
SHELLCHECK_VERSION: v0.7.1
|
|
||||||
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
|
|
||||||
- find . -name '*.sh' -not -path './.git/*' | xargs shellcheck --severity error
|
|
||||||
except: ['triggers', 'master']
|
|
|
@ -1,235 +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 -chdir="contrib/terraform/$PROVIDER" init
|
|
||||||
# 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
|
|
||||||
- mkdir -p contrib/terraform/$PROVIDER/group_vars
|
|
||||||
# Random subnet to avoid routing conflicts
|
|
||||||
- export TF_VAR_subnet_cidr="10.$(( $RANDOM % 256 )).$(( $RANDOM % 256 )).0/24"
|
|
||||||
|
|
||||||
.terraform_validate:
|
|
||||||
extends: .terraform_install
|
|
||||||
stage: unit-tests
|
|
||||||
tags: [light]
|
|
||||||
only: ['master', /^pr-.*$/]
|
|
||||||
script:
|
|
||||||
- terraform -chdir="contrib/terraform/$PROVIDER" validate
|
|
||||||
- terraform -chdir="contrib/terraform/$PROVIDER" fmt -check -diff
|
|
||||||
|
|
||||||
.terraform_apply:
|
|
||||||
extends: .terraform_install
|
|
||||||
tags: [light]
|
|
||||||
stage: deploy-part3
|
|
||||||
when: manual
|
|
||||||
only: [/^pr-.*$/]
|
|
||||||
artifacts:
|
|
||||||
when: always
|
|
||||||
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: $TERRAFORM_VERSION
|
|
||||||
PROVIDER: openstack
|
|
||||||
CLUSTER: $CI_COMMIT_REF_NAME
|
|
||||||
|
|
||||||
tf-validate-metal:
|
|
||||||
extends: .terraform_validate
|
|
||||||
variables:
|
|
||||||
TF_VERSION: $TERRAFORM_VERSION
|
|
||||||
PROVIDER: metal
|
|
||||||
CLUSTER: $CI_COMMIT_REF_NAME
|
|
||||||
|
|
||||||
tf-validate-aws:
|
|
||||||
extends: .terraform_validate
|
|
||||||
variables:
|
|
||||||
TF_VERSION: $TERRAFORM_VERSION
|
|
||||||
PROVIDER: aws
|
|
||||||
CLUSTER: $CI_COMMIT_REF_NAME
|
|
||||||
|
|
||||||
tf-validate-exoscale:
|
|
||||||
extends: .terraform_validate
|
|
||||||
variables:
|
|
||||||
TF_VERSION: $TERRAFORM_VERSION
|
|
||||||
PROVIDER: exoscale
|
|
||||||
|
|
||||||
tf-validate-vsphere:
|
|
||||||
extends: .terraform_validate
|
|
||||||
variables:
|
|
||||||
TF_VERSION: $TERRAFORM_VERSION
|
|
||||||
PROVIDER: vsphere
|
|
||||||
CLUSTER: $CI_COMMIT_REF_NAME
|
|
||||||
|
|
||||||
tf-validate-upcloud:
|
|
||||||
extends: .terraform_validate
|
|
||||||
variables:
|
|
||||||
TF_VERSION: $TERRAFORM_VERSION
|
|
||||||
PROVIDER: upcloud
|
|
||||||
CLUSTER: $CI_COMMIT_REF_NAME
|
|
||||||
|
|
||||||
# tf-packet-ubuntu16-default:
|
|
||||||
# extends: .terraform_apply
|
|
||||||
# variables:
|
|
||||||
# TF_VERSION: $TERRAFORM_VERSION
|
|
||||||
# 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: $TERRAFORM_VERSION
|
|
||||||
# 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"
|
|
||||||
|
|
||||||
# Elastx is generously donating resources for Kubespray on Openstack CI
|
|
||||||
# Contacts: @gix @bl0m1
|
|
||||||
.elastx_variables: &elastx_variables
|
|
||||||
OS_AUTH_URL: https://ops.elastx.cloud:5000
|
|
||||||
OS_PROJECT_ID: 564c6b461c6b44b1bb19cdb9c2d928e4
|
|
||||||
OS_PROJECT_NAME: kubespray_ci
|
|
||||||
OS_USER_DOMAIN_NAME: Default
|
|
||||||
OS_PROJECT_DOMAIN_ID: default
|
|
||||||
OS_USERNAME: kubespray@root314.com
|
|
||||||
OS_REGION_NAME: se-sto
|
|
||||||
OS_INTERFACE: public
|
|
||||||
OS_IDENTITY_API_VERSION: "3"
|
|
||||||
TF_VAR_router_id: "ab95917c-41fb-4881-b507-3a6dfe9403df"
|
|
||||||
|
|
||||||
tf-elastx_cleanup:
|
|
||||||
stage: unit-tests
|
|
||||||
tags: [light]
|
|
||||||
image: python
|
|
||||||
variables:
|
|
||||||
<<: *elastx_variables
|
|
||||||
before_script:
|
|
||||||
- pip install -r scripts/openstack-cleanup/requirements.txt
|
|
||||||
script:
|
|
||||||
- ./scripts/openstack-cleanup/main.py
|
|
||||||
|
|
||||||
tf-elastx_ubuntu18-calico:
|
|
||||||
extends: .terraform_apply
|
|
||||||
stage: deploy-part3
|
|
||||||
when: on_success
|
|
||||||
allow_failure: true
|
|
||||||
variables:
|
|
||||||
<<: *elastx_variables
|
|
||||||
TF_VERSION: $TERRAFORM_VERSION
|
|
||||||
PROVIDER: openstack
|
|
||||||
CLUSTER: $CI_COMMIT_REF_NAME
|
|
||||||
ANSIBLE_TIMEOUT: "60"
|
|
||||||
SSH_USER: ubuntu
|
|
||||||
TF_VAR_number_of_k8s_masters: "1"
|
|
||||||
TF_VAR_number_of_k8s_masters_no_floating_ip: "0"
|
|
||||||
TF_VAR_number_of_k8s_masters_no_floating_ip_no_etcd: "0"
|
|
||||||
TF_VAR_number_of_etcd: "0"
|
|
||||||
TF_VAR_number_of_k8s_nodes: "1"
|
|
||||||
TF_VAR_number_of_k8s_nodes_no_floating_ip: "0"
|
|
||||||
TF_VAR_number_of_gfs_nodes_no_floating_ip: "0"
|
|
||||||
TF_VAR_number_of_bastions: "0"
|
|
||||||
TF_VAR_number_of_k8s_masters_no_etcd: "0"
|
|
||||||
TF_VAR_floatingip_pool: "elx-public1"
|
|
||||||
TF_VAR_dns_nameservers: '["1.1.1.1", "8.8.8.8", "8.8.4.4"]'
|
|
||||||
TF_VAR_use_access_ip: "0"
|
|
||||||
TF_VAR_external_net: "600b8501-78cb-4155-9c9f-23dfcba88828"
|
|
||||||
TF_VAR_network_name: "ci-$CI_JOB_ID"
|
|
||||||
TF_VAR_az_list: '["sto1"]'
|
|
||||||
TF_VAR_az_list_node: '["sto1"]'
|
|
||||||
TF_VAR_flavor_k8s_master: 3f73fc93-ec61-4808-88df-2580d94c1a9b # v1-standard-2
|
|
||||||
TF_VAR_flavor_k8s_node: 3f73fc93-ec61-4808-88df-2580d94c1a9b # v1-standard-2
|
|
||||||
TF_VAR_image: ubuntu-18.04-server-latest
|
|
||||||
TF_VAR_k8s_allowed_remote_ips: '["0.0.0.0/0"]'
|
|
||||||
|
|
||||||
# OVH voucher expired, commenting job until things are sorted out
|
|
||||||
|
|
||||||
# tf-ovh_cleanup:
|
|
||||||
# stage: unit-tests
|
|
||||||
# tags: [light]
|
|
||||||
# image: python
|
|
||||||
# environment: ovh
|
|
||||||
# variables:
|
|
||||||
# <<: *ovh_variables
|
|
||||||
# before_script:
|
|
||||||
# - pip install -r scripts/openstack-cleanup/requirements.txt
|
|
||||||
# script:
|
|
||||||
# - ./scripts/openstack-cleanup/main.py
|
|
||||||
|
|
||||||
# tf-ovh_ubuntu18-calico:
|
|
||||||
# extends: .terraform_apply
|
|
||||||
# when: on_success
|
|
||||||
# environment: ovh
|
|
||||||
# variables:
|
|
||||||
# <<: *ovh_variables
|
|
||||||
# TF_VERSION: $TERRAFORM_VERSION
|
|
||||||
# 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"]'
|
|
|
@ -1,67 +0,0 @@
|
||||||
---
|
|
||||||
|
|
||||||
.vagrant:
|
|
||||||
extends: .testcases
|
|
||||||
variables:
|
|
||||||
CI_PLATFORM: "vagrant"
|
|
||||||
SSH_USER: "vagrant"
|
|
||||||
VAGRANT_DEFAULT_PROVIDER: "libvirt"
|
|
||||||
KUBESPRAY_VAGRANT_CONFIG: tests/files/${CI_JOB_NAME}.rb
|
|
||||||
tags: [c3.small.x86]
|
|
||||||
only: [/^pr-.*$/]
|
|
||||||
except: ['triggers']
|
|
||||||
image: quay.io/kubespray/vagrant:$KUBESPRAY_VERSION
|
|
||||||
services: []
|
|
||||||
before_script:
|
|
||||||
- apt-get update && apt-get install -y python3-pip
|
|
||||||
- update-alternatives --install /usr/bin/python python /usr/bin/python3 10
|
|
||||||
- python -m pip uninstall -y ansible ansible-base ansible-core
|
|
||||||
- python -m pip install -r tests/requirements.txt
|
|
||||||
- ./tests/scripts/vagrant_clean.sh
|
|
||||||
script:
|
|
||||||
- ./tests/scripts/testcases_run.sh
|
|
||||||
after_script:
|
|
||||||
- chronic ./tests/scripts/testcases_cleanup.sh
|
|
||||||
allow_failure: true
|
|
||||||
|
|
||||||
vagrant_ubuntu18-calico-dual-stack:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .vagrant
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
vagrant_ubuntu18-flannel:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .vagrant
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
vagrant_ubuntu18-weave-medium:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .vagrant
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
vagrant_ubuntu20-flannel:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .vagrant
|
|
||||||
when: on_success
|
|
||||||
allow_failure: false
|
|
||||||
|
|
||||||
vagrant_ubuntu16-kube-router-sep:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .vagrant
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
# Service proxy test fails connectivity testing
|
|
||||||
vagrant_ubuntu16-kube-router-svc-proxy:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .vagrant
|
|
||||||
when: manual
|
|
||||||
|
|
||||||
vagrant_fedora35-kube-router:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .vagrant
|
|
||||||
when: on_success
|
|
||||||
|
|
||||||
vagrant_centos7-kube-router:
|
|
||||||
stage: deploy-part2
|
|
||||||
extends: .vagrant
|
|
||||||
when: manual
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
MD013: false
|
|
||||||
MD029: false
|
|
|
@ -1,48 +0,0 @@
|
||||||
---
|
|
||||||
repos:
|
|
||||||
- repo: https://github.com/adrienverge/yamllint.git
|
|
||||||
rev: v1.27.1
|
|
||||||
hooks:
|
|
||||||
- id: yamllint
|
|
||||||
args: [--strict]
|
|
||||||
|
|
||||||
- repo: https://github.com/markdownlint/markdownlint
|
|
||||||
rev: v0.11.0
|
|
||||||
hooks:
|
|
||||||
- id: markdownlint
|
|
||||||
args: [ -r, "~MD013,~MD029" ]
|
|
||||||
exclude: "^.git"
|
|
||||||
|
|
||||||
- repo: local
|
|
||||||
hooks:
|
|
||||||
- id: ansible-lint
|
|
||||||
name: ansible-lint
|
|
||||||
entry: ansible-lint -v
|
|
||||||
language: python
|
|
||||||
pass_filenames: false
|
|
||||||
additional_dependencies:
|
|
||||||
- .[community]
|
|
||||||
|
|
||||||
- id: ansible-syntax-check
|
|
||||||
name: ansible-syntax-check
|
|
||||||
entry: env ANSIBLE_INVENTORY=inventory/local-tests.cfg ANSIBLE_REMOTE_USER=root ANSIBLE_BECOME="true" ANSIBLE_BECOME_USER=root ANSIBLE_VERBOSITY="3" ansible-playbook --syntax-check
|
|
||||||
language: python
|
|
||||||
files: "^cluster.yml|^upgrade-cluster.yml|^reset.yml|^extra_playbooks/upgrade-only-k8s.yml"
|
|
||||||
|
|
||||||
- id: tox-inventory-builder
|
|
||||||
name: tox-inventory-builder
|
|
||||||
entry: bash -c "cd contrib/inventory_builder && tox"
|
|
||||||
language: python
|
|
||||||
pass_filenames: false
|
|
||||||
|
|
||||||
- id: check-readme-versions
|
|
||||||
name: check-readme-versions
|
|
||||||
entry: tests/scripts/check_readme_versions.sh
|
|
||||||
language: script
|
|
||||||
pass_filenames: false
|
|
||||||
|
|
||||||
- id: ci-matrix
|
|
||||||
name: ci-matrix
|
|
||||||
entry: tests/scripts/md-table/test.sh
|
|
||||||
language: script
|
|
||||||
pass_filenames: false
|
|
150
.travis.yml
Normal file
150
.travis.yml
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
git:
|
||||||
|
depth: 5
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
GCE_USER=travis
|
||||||
|
SSH_USER=$GCE_USER
|
||||||
|
TEST_ID=$TRAVIS_JOB_NUMBER
|
||||||
|
CONTAINER_ENGINE=docker
|
||||||
|
PRIVATE_KEY=$GCE_PRIVATE_KEY
|
||||||
|
ANSIBLE_KEEP_REMOTE_FILES=1
|
||||||
|
matrix:
|
||||||
|
# Debian Jessie
|
||||||
|
- >-
|
||||||
|
KUBE_NETWORK_PLUGIN=flannel
|
||||||
|
CLOUD_IMAGE=debian-8-kubespray
|
||||||
|
CLOUD_REGION=europe-west1-b
|
||||||
|
- >-
|
||||||
|
KUBE_NETWORK_PLUGIN=calico
|
||||||
|
CLOUD_IMAGE=debian-8-kubespray
|
||||||
|
CLOUD_REGION=us-central1-c
|
||||||
|
- >-
|
||||||
|
KUBE_NETWORK_PLUGIN=weave
|
||||||
|
CLOUD_IMAGE=debian-8-kubespray
|
||||||
|
CLOUD_REGION=us-east1-d
|
||||||
|
|
||||||
|
# Centos 7
|
||||||
|
- >-
|
||||||
|
KUBE_NETWORK_PLUGIN=flannel
|
||||||
|
CLOUD_IMAGE=centos-7-sudo
|
||||||
|
CLOUD_REGION=asia-east1-c
|
||||||
|
|
||||||
|
- >-
|
||||||
|
KUBE_NETWORK_PLUGIN=calico
|
||||||
|
CLOUD_IMAGE=centos-7-sudo
|
||||||
|
CLOUD_REGION=europe-west1-b
|
||||||
|
|
||||||
|
- >-
|
||||||
|
KUBE_NETWORK_PLUGIN=weave
|
||||||
|
CLOUD_IMAGE=centos-7-sudo
|
||||||
|
CLOUD_REGION=us-central1-c
|
||||||
|
|
||||||
|
# Redhat 7
|
||||||
|
- >-
|
||||||
|
KUBE_NETWORK_PLUGIN=flannel
|
||||||
|
CLOUD_IMAGE=rhel-7-sudo
|
||||||
|
CLOUD_REGION=us-east1-d
|
||||||
|
|
||||||
|
- >-
|
||||||
|
KUBE_NETWORK_PLUGIN=calico
|
||||||
|
CLOUD_IMAGE=rhel-7-sudo
|
||||||
|
CLOUD_REGION=asia-east1-c
|
||||||
|
|
||||||
|
- >-
|
||||||
|
KUBE_NETWORK_PLUGIN=weave
|
||||||
|
CLOUD_IMAGE=rhel-7-sudo
|
||||||
|
CLOUD_REGION=europe-west1-b
|
||||||
|
|
||||||
|
# Ubuntu 14.04
|
||||||
|
- >-
|
||||||
|
KUBE_NETWORK_PLUGIN=flannel
|
||||||
|
CLOUD_IMAGE=ubuntu-1404-trusty
|
||||||
|
CLOUD_REGION=us-central1-c
|
||||||
|
- >-
|
||||||
|
KUBE_NETWORK_PLUGIN=calico
|
||||||
|
CLOUD_IMAGE=ubuntu-1404-trusty
|
||||||
|
CLOUD_REGION=us-east1-d
|
||||||
|
- >-
|
||||||
|
KUBE_NETWORK_PLUGIN=weave
|
||||||
|
CLOUD_IMAGE=ubuntu-1404-trusty
|
||||||
|
CLOUD_REGION=asia-east1-c
|
||||||
|
|
||||||
|
# Ubuntu 15.10
|
||||||
|
- >-
|
||||||
|
KUBE_NETWORK_PLUGIN=flannel
|
||||||
|
CLOUD_IMAGE=ubuntu-1510-wily
|
||||||
|
CLOUD_REGION=europe-west1-b
|
||||||
|
- >-
|
||||||
|
KUBE_NETWORK_PLUGIN=calico
|
||||||
|
CLOUD_IMAGE=ubuntu-1510-wily
|
||||||
|
CLOUD_REGION=us-central1-a
|
||||||
|
- >-
|
||||||
|
KUBE_NETWORK_PLUGIN=weave
|
||||||
|
CLOUD_IMAGE=ubuntu-1510-wily
|
||||||
|
CLOUD_REGION=us-east1-d
|
||||||
|
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
allow_failures:
|
||||||
|
- env: KUBE_NETWORK_PLUGIN=weave CLOUD_IMAGE=ubuntu-1404-trusty CLOUD_REGION=asia-east1-c
|
||||||
|
- env: KUBE_NETWORK_PLUGIN=calico CLOUD_IMAGE=ubuntu-1404-trusty CLOUD_REGION=us-east1-d
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
# Install Ansible.
|
||||||
|
- pip install --user boto -U
|
||||||
|
- pip install --user ansible
|
||||||
|
- pip install --user netaddr
|
||||||
|
- pip install --user apache-libcloud
|
||||||
|
|
||||||
|
cache:
|
||||||
|
- directories:
|
||||||
|
- $HOME/.cache/pip
|
||||||
|
- $HOME/.local
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- echo "RUN $TRAVIS_JOB_NUMBER $KUBE_NETWORK_PLUGIN $CONTAINER_ENGINE "
|
||||||
|
- mkdir -p $HOME/.ssh
|
||||||
|
- echo $PRIVATE_KEY | base64 -d > $HOME/.ssh/id_rsa
|
||||||
|
- echo $GCE_PEM_FILE | base64 -d > $HOME/.ssh/gce
|
||||||
|
- chmod 400 $HOME/.ssh/id_rsa
|
||||||
|
- chmod 755 $HOME/.local/bin/ansible-playbook
|
||||||
|
- $HOME/.local/bin/ansible-playbook --version
|
||||||
|
- cp tests/ansible.cfg .
|
||||||
|
# - "echo $HOME/.local/bin/ansible-playbook -i inventory.ini -u $SSH_USER -e ansible_ssh_user=$SSH_USER $SSH_ARGS -b --become-user=root -e '{\"cloud_provider\": true}' $LOG_LEVEL -e kube_network_plugin=${KUBE_NETWORK_PLUGIN} setup-kubernetes/cluster.yml"
|
||||||
|
|
||||||
|
script:
|
||||||
|
- >
|
||||||
|
$HOME/.local/bin/ansible-playbook tests/cloud_playbooks/create-gce.yml -i tests/local_inventory/hosts -c local $LOG_LEVEL
|
||||||
|
-e test_id=${TEST_ID}
|
||||||
|
-e kube_network_plugin=${KUBE_NETWORK_PLUGIN}
|
||||||
|
-e gce_project_id=${GCE_PROJECT_ID}
|
||||||
|
-e gce_service_account_email=${GCE_ACCOUNT}
|
||||||
|
-e gce_pem_file=${HOME}/.ssh/gce
|
||||||
|
-e cloud_image=${CLOUD_IMAGE}
|
||||||
|
-e inventory_path=${PWD}/inventory/inventory.ini
|
||||||
|
-e cloud_region=${CLOUD_REGION}
|
||||||
|
|
||||||
|
# Create cluster
|
||||||
|
- "$HOME/.local/bin/ansible-playbook -i inventory/inventory.ini -u $SSH_USER -e ansible_ssh_user=$SSH_USER $SSH_ARGS -b --become-user=root -e '{\"cloud_provider\": true}' $LOG_LEVEL -e kube_network_plugin=${KUBE_NETWORK_PLUGIN} cluster.yml"
|
||||||
|
# Tests Cases
|
||||||
|
## Test Master API
|
||||||
|
- $HOME/.local/bin/ansible-playbook -i inventory/inventory.ini tests/testcases/010_check-apiserver.yml $LOG_LEVEL
|
||||||
|
## Create a POD
|
||||||
|
- $HOME/.local/bin/ansible-playbook -i inventory/inventory.ini -u $SSH_USER -e ansible_ssh_user=$SSH_USER $SSH_ARGS -b --become-user=root tests/testcases/020_check-create-pod.yml $LOG_LEVEL
|
||||||
|
## Ping the between 2 pod
|
||||||
|
- $HOME/.local/bin/ansible-playbook -i inventory/inventory.ini -u $SSH_USER -e ansible_ssh_user=$SSH_USER $SSH_ARGS -b --become-user=root tests/testcases/030_check-network.yml $LOG_LEVEL
|
||||||
|
|
||||||
|
after_script:
|
||||||
|
- >
|
||||||
|
$HOME/.local/bin/ansible-playbook -i inventory/inventory.ini tests/cloud_playbooks/delete-gce.yml -c local $LOG_LEVEL
|
||||||
|
-e test_id=${TEST_ID}
|
||||||
|
-e kube_network_plugin=${KUBE_NETWORK_PLUGIN}
|
||||||
|
-e gce_project_id=${GCE_PROJECT_ID}
|
||||||
|
-e gce_service_account_email=${GCE_ACCOUNT}
|
||||||
|
-e gce_pem_file=${HOME}/.ssh/gce
|
||||||
|
-e cloud_image=${CLOUD_IMAGE}
|
||||||
|
-e inventory_path=${PWD}/inventory/inventory.ini
|
||||||
|
-e cloud_region=${CLOUD_REGION}
|
19
.yamllint
19
.yamllint
|
@ -1,19 +0,0 @@
|
||||||
---
|
|
||||||
extends: default
|
|
||||||
|
|
||||||
ignore: |
|
|
||||||
.git/
|
|
||||||
|
|
||||||
rules:
|
|
||||||
braces:
|
|
||||||
min-spaces-inside: 0
|
|
||||||
max-spaces-inside: 1
|
|
||||||
brackets:
|
|
||||||
min-spaces-inside: 0
|
|
||||||
max-spaces-inside: 1
|
|
||||||
indentation:
|
|
||||||
spaces: 2
|
|
||||||
indent-sequences: consistent
|
|
||||||
line-length: disable
|
|
||||||
new-line-at-end-of-file: disable
|
|
||||||
truthy: disable
|
|
1
CNAME
1
CNAME
|
@ -1 +0,0 @@
|
||||||
kubespray.io
|
|
|
@ -1,46 +0,0 @@
|
||||||
# Contributing guidelines
|
|
||||||
|
|
||||||
## 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 set up a python virtual env with the necessary dependencies:
|
|
||||||
|
|
||||||
```ShellSession
|
|
||||||
virtualenv venv
|
|
||||||
source venv/bin/activate
|
|
||||||
pip install -r tests/requirements.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Linting
|
|
||||||
|
|
||||||
Kubespray uses [pre-commit](https://pre-commit.com) hook configuration to run several linters, please install this tool and use it to run validation tests before submitting a PR.
|
|
||||||
|
|
||||||
```ShellSession
|
|
||||||
pre-commit install
|
|
||||||
pre-commit run -a # To run pre-commit hook on all files in the repository, even if they were not modified
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 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
|
|
||||||
|
|
||||||
1. Submit an issue describing your proposed change to the repo in question.
|
|
||||||
2. The [repo owners](OWNERS) will respond to your issue promptly.
|
|
||||||
3. Fork the desired repo, develop and test your code changes.
|
|
||||||
4. Install [pre-commit](https://pre-commit.com) and install it in your development repo.
|
|
||||||
5. Addess any pre-commit validation failures.
|
|
||||||
6. Sign the CNCF CLA (<https://git.k8s.io/community/CLA.md#the-contributor-license-agreement>)
|
|
||||||
7. Submit a pull request.
|
|
||||||
8. Work with the reviewers on their suggestions.
|
|
||||||
9. Ensure to rebase to the HEAD of your target branch and squash un-necessary commits (<https://blog.carbonfive.com/always-squash-and-rebase-your-git-commits/>) before final merger of your contribution.
|
|
37
Dockerfile
37
Dockerfile
|
@ -1,37 +0,0 @@
|
||||||
# Use imutable image tags rather than mutable tags (like ubuntu:20.04)
|
|
||||||
FROM ubuntu:focal-20220531
|
|
||||||
|
|
||||||
ARG ARCH=amd64
|
|
||||||
ARG TZ=Etc/UTC
|
|
||||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
|
||||||
|
|
||||||
RUN apt update -y \
|
|
||||||
&& apt install -y \
|
|
||||||
libssl-dev python3-dev sshpass apt-transport-https jq moreutils \
|
|
||||||
ca-certificates curl gnupg2 software-properties-common python3-pip unzip rsync git \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
RUN curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add - \
|
|
||||||
&& add-apt-repository \
|
|
||||||
"deb [arch=$ARCH] https://download.docker.com/linux/ubuntu \
|
|
||||||
$(lsb_release -cs) \
|
|
||||||
stable" \
|
|
||||||
&& apt update -y && apt-get install --no-install-recommends -y docker-ce \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Some tools like yamllint need this
|
|
||||||
# Pip needs this as well at the moment to install ansible
|
|
||||||
# (and potentially other packages)
|
|
||||||
# See: https://github.com/pypa/pip/issues/10219
|
|
||||||
ENV LANG=C.UTF-8
|
|
||||||
|
|
||||||
WORKDIR /kubespray
|
|
||||||
COPY . .
|
|
||||||
RUN /usr/bin/python3 -m pip install --no-cache-dir pip -U \
|
|
||||||
&& /usr/bin/python3 -m pip install --no-cache-dir -r tests/requirements.txt \
|
|
||||||
&& python3 -m pip install --no-cache-dir -r requirements.txt \
|
|
||||||
&& update-alternatives --install /usr/bin/python python /usr/bin/python3 1
|
|
||||||
|
|
||||||
RUN KUBE_VERSION=$(sed -n 's/^kube_version: //p' roles/kubespray-defaults/defaults/main.yaml) \
|
|
||||||
&& curl -LO https://storage.googleapis.com/kubernetes-release/release/$KUBE_VERSION/bin/linux/$ARCH/kubectl \
|
|
||||||
&& chmod a+x kubectl \
|
|
||||||
&& mv kubectl /usr/local/bin/kubectl
|
|
7
Makefile
7
Makefile
|
@ -1,7 +0,0 @@
|
||||||
mitogen:
|
|
||||||
@echo Mitogen support is deprecated.
|
|
||||||
@echo Please run the following command manually:
|
|
||||||
@echo ansible-playbook -c local mitogen.yml -vv
|
|
||||||
clean:
|
|
||||||
rm -rf dist/
|
|
||||||
rm *.retry
|
|
8
OWNERS
8
OWNERS
|
@ -1,8 +0,0 @@
|
||||||
# See the OWNERS docs at https://go.k8s.io/owners
|
|
||||||
|
|
||||||
approvers:
|
|
||||||
- kubespray-approvers
|
|
||||||
reviewers:
|
|
||||||
- kubespray-reviewers
|
|
||||||
emeritus_approvers:
|
|
||||||
- kubespray-emeritus_approvers
|
|
|
@ -1,26 +0,0 @@
|
||||||
aliases:
|
|
||||||
kubespray-approvers:
|
|
||||||
- mattymo
|
|
||||||
- chadswen
|
|
||||||
- mirwan
|
|
||||||
- miouge1
|
|
||||||
- luckysb
|
|
||||||
- floryut
|
|
||||||
- oomichi
|
|
||||||
- cristicalin
|
|
||||||
- liupeng0518
|
|
||||||
- yankay
|
|
||||||
kubespray-reviewers:
|
|
||||||
- holmsten
|
|
||||||
- bozzo
|
|
||||||
- eppo
|
|
||||||
- oomichi
|
|
||||||
- jayonlau
|
|
||||||
- cristicalin
|
|
||||||
- liupeng0518
|
|
||||||
- yankay
|
|
||||||
kubespray-emeritus_approvers:
|
|
||||||
- riverzhang
|
|
||||||
- atoms
|
|
||||||
- ant31
|
|
||||||
- woopstar
|
|
261
README.md
261
README.md
|
@ -1,261 +1,6 @@
|
||||||
# Deploy a Production Ready Kubernetes Cluster
|
|
||||||
|
|
||||||
![Kubernetes Logo](https://raw.githubusercontent.com/kubernetes-sigs/kubespray/master/docs/img/kubernetes-logo.png)
|
![Kubespray Logo](http://s9.postimg.org/md5dyjl67/kubespray_logoandkubespray_small.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**.
|
The documentation can be found [THERE](https://docs.kubespray.io)
|
||||||
You can get your invite [here](http://slack.k8s.io/)
|
|
||||||
|
|
||||||
- Can be deployed on **[AWS](docs/aws.md), GCE, [Azure](docs/azure.md), [OpenStack](docs/openstack.md), [vSphere](docs/vsphere.md), [Equinix Metal](docs/equinix-metal.md) (bare metal), Oracle Cloud Infrastructure (Experimental), or Baremetal**
|
[![Build Status](https://travis-ci.org/kubespray/kubespray.svg)](https://travis-ci.org/kubespray/kubespray)
|
||||||
- **Highly available** cluster
|
|
||||||
- **Composable** (Choice of the network plugin for instance)
|
|
||||||
- Supports most popular **Linux distributions**
|
|
||||||
- **Continuous integration tests**
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
To deploy the cluster you can use :
|
|
||||||
|
|
||||||
### Ansible
|
|
||||||
|
|
||||||
#### Usage
|
|
||||||
|
|
||||||
Install Ansible according to [Ansible installation guide](/docs/ansible.md#installing-ansible)
|
|
||||||
then run the following steps:
|
|
||||||
|
|
||||||
```ShellSession
|
|
||||||
# Copy ``inventory/sample`` as ``inventory/mycluster``
|
|
||||||
cp -rfp inventory/sample inventory/mycluster
|
|
||||||
|
|
||||||
# Update Ansible inventory file with inventory builder
|
|
||||||
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[@]}
|
|
||||||
|
|
||||||
# Review and change parameters under ``inventory/mycluster/group_vars``
|
|
||||||
cat inventory/mycluster/group_vars/all/all.yml
|
|
||||||
cat inventory/mycluster/group_vars/k8s_cluster/k8s-cluster.yml
|
|
||||||
|
|
||||||
# Deploy Kubespray with Ansible Playbook - run the playbook as root
|
|
||||||
# The option `--become` is required, as for example writing SSL keys in /etc/,
|
|
||||||
# installing packages and interacting with various systemd daemons.
|
|
||||||
# Without --become the playbook will fail to run!
|
|
||||||
ansible-playbook -i inventory/mycluster/hosts.yaml --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).
|
|
||||||
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.
|
|
||||||
```
|
|
||||||
|
|
||||||
probably pointing on a task depending on a module present in requirements.txt.
|
|
||||||
|
|
||||||
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.
|
|
||||||
A workaround consists of setting `ANSIBLE_LIBRARY` and `ANSIBLE_MODULE_UTILS` environment variables respectively to the `ansible/modules` and `ansible/module_utils` subdirectories of pip packages installation location, which can be found in the Location field of the output of `pip show [package]` before executing `ansible-playbook`.
|
|
||||||
|
|
||||||
A simple way to ensure you get all the correct version of Ansible is to use the [pre-built docker image from Quay](https://quay.io/repository/kubespray/kubespray?tab=tags).
|
|
||||||
You will then need to use [bind mounts](https://docs.docker.com/storage/bind-mounts/) to get the inventory and ssh key into the container, like this:
|
|
||||||
|
|
||||||
```ShellSession
|
|
||||||
git checkout v2.20.0
|
|
||||||
docker pull quay.io/kubespray/kubespray:v2.20.0
|
|
||||||
docker run --rm -it --mount type=bind,source="$(pwd)"/inventory/sample,dst=/inventory \
|
|
||||||
--mount type=bind,source="${HOME}"/.ssh/id_rsa,dst=/root/.ssh/id_rsa \
|
|
||||||
quay.io/kubespray/kubespray:v2.20.0 bash
|
|
||||||
# Inside the container you may now run the kubespray playbooks:
|
|
||||||
ansible-playbook -i /inventory/inventory.ini --private-key /root/.ssh/id_rsa cluster.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
### Vagrant
|
|
||||||
|
|
||||||
For Vagrant we need to install python dependencies for provisioning tasks.
|
|
||||||
Check if Python and pip are installed:
|
|
||||||
|
|
||||||
```ShellSession
|
|
||||||
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/>
|
|
||||||
|
|
||||||
Install Ansible according to [Ansible installation guide](/docs/ansible.md#installing-ansible)
|
|
||||||
then run the following step:
|
|
||||||
|
|
||||||
```ShellSession
|
|
||||||
vagrant up
|
|
||||||
```
|
|
||||||
|
|
||||||
## Documents
|
|
||||||
|
|
||||||
- [Requirements](#requirements)
|
|
||||||
- [Kubespray vs ...](docs/comparisons.md)
|
|
||||||
- [Getting started](docs/getting-started.md)
|
|
||||||
- [Setting up your first cluster](docs/setting-up-your-first-cluster.md)
|
|
||||||
- [Ansible inventory and tags](docs/ansible.md)
|
|
||||||
- [Integration with existing ansible repo](docs/integration.md)
|
|
||||||
- [Deployment data variables](docs/vars.md)
|
|
||||||
- [DNS stack](docs/dns-stack.md)
|
|
||||||
- [HA mode](docs/ha-mode.md)
|
|
||||||
- [Network plugins](#network-plugins)
|
|
||||||
- [Vagrant install](docs/vagrant.md)
|
|
||||||
- [Flatcar Container Linux bootstrap](docs/flatcar.md)
|
|
||||||
- [Fedora CoreOS bootstrap](docs/fcos.md)
|
|
||||||
- [Debian Jessie setup](docs/debian.md)
|
|
||||||
- [openSUSE setup](docs/opensuse.md)
|
|
||||||
- [Downloaded artifacts](docs/downloads.md)
|
|
||||||
- [Cloud providers](docs/cloud.md)
|
|
||||||
- [OpenStack](docs/openstack.md)
|
|
||||||
- [AWS](docs/aws.md)
|
|
||||||
- [Azure](docs/azure.md)
|
|
||||||
- [vSphere](docs/vsphere.md)
|
|
||||||
- [Equinix Metal](docs/equinix-metal.md)
|
|
||||||
- [Large deployments](docs/large-deployments.md)
|
|
||||||
- [Adding/replacing a node](docs/nodes.md)
|
|
||||||
- [Upgrades basics](docs/upgrades.md)
|
|
||||||
- [Air-Gap installation](docs/offline-environment.md)
|
|
||||||
- [NTP](docs/ntp.md)
|
|
||||||
- [Hardening](docs/hardening.md)
|
|
||||||
- [Mirror](docs/mirror.md)
|
|
||||||
- [Roadmap](docs/roadmap.md)
|
|
||||||
|
|
||||||
## Supported Linux Distributions
|
|
||||||
|
|
||||||
- **Flatcar Container Linux by Kinvolk**
|
|
||||||
- **Debian** Bullseye, Buster, Jessie, Stretch
|
|
||||||
- **Ubuntu** 16.04, 18.04, 20.04, 22.04
|
|
||||||
- **CentOS/RHEL** 7, [8, 9](docs/centos.md#centos-8)
|
|
||||||
- **Fedora** 35, 36
|
|
||||||
- **Fedora CoreOS** (see [fcos Note](docs/fcos.md))
|
|
||||||
- **openSUSE** Leap 15.x/Tumbleweed
|
|
||||||
- **Oracle Linux** 7, [8, 9](docs/centos.md#centos-8)
|
|
||||||
- **Alma Linux** [8, 9](docs/centos.md#centos-8)
|
|
||||||
- **Rocky Linux** [8, 9](docs/centos.md#centos-8)
|
|
||||||
- **Kylin Linux Advanced Server V10** (experimental: see [kylin linux notes](docs/kylinlinux.md))
|
|
||||||
- **Amazon Linux 2** (experimental: see [amazon linux notes](docs/amazonlinux.md))
|
|
||||||
- **UOS Linux** (experimental: see [uos linux notes](docs/uoslinux.md))
|
|
||||||
- **openEuler** (experimental: see [openEuler notes](docs/openeuler.md))
|
|
||||||
|
|
||||||
Note: Upstart/SysV init based OS types are not supported.
|
|
||||||
|
|
||||||
## Supported Components
|
|
||||||
|
|
||||||
- Core
|
|
||||||
- [kubernetes](https://github.com/kubernetes/kubernetes) v1.25.5
|
|
||||||
- [etcd](https://github.com/etcd-io/etcd) v3.5.6
|
|
||||||
- [docker](https://www.docker.com/) v20.10 (see note)
|
|
||||||
- [containerd](https://containerd.io/) v1.6.14
|
|
||||||
- [cri-o](http://cri-o.io/) v1.24 (experimental: see [CRI-O Note](docs/cri-o.md). Only on fedora, ubuntu and centos based OS)
|
|
||||||
- Network Plugin
|
|
||||||
- [cni-plugins](https://github.com/containernetworking/plugins) v1.1.1
|
|
||||||
- [calico](https://github.com/projectcalico/calico) v3.24.5
|
|
||||||
- [canal](https://github.com/projectcalico/canal) (given calico/flannel versions)
|
|
||||||
- [cilium](https://github.com/cilium/cilium) v1.12.1
|
|
||||||
- [flannel](https://github.com/flannel-io/flannel) v0.19.2
|
|
||||||
- [kube-ovn](https://github.com/alauda/kube-ovn) v1.10.7
|
|
||||||
- [kube-router](https://github.com/cloudnativelabs/kube-router) v1.5.1
|
|
||||||
- [multus](https://github.com/intel/multus-cni) v3.8
|
|
||||||
- [weave](https://github.com/weaveworks/weave) v2.8.1
|
|
||||||
- [kube-vip](https://github.com/kube-vip/kube-vip) v0.5.5
|
|
||||||
- Application
|
|
||||||
- [cert-manager](https://github.com/jetstack/cert-manager) v1.10.1
|
|
||||||
- [coredns](https://github.com/coredns/coredns) v1.9.3
|
|
||||||
- [ingress-nginx](https://github.com/kubernetes/ingress-nginx) v1.5.1
|
|
||||||
- [krew](https://github.com/kubernetes-sigs/krew) v0.4.3
|
|
||||||
- [argocd](https://argoproj.github.io/) v2.4.16
|
|
||||||
- [helm](https://helm.sh/) v3.9.4
|
|
||||||
- [metallb](https://metallb.universe.tf/) v0.12.1
|
|
||||||
- [registry](https://github.com/distribution/distribution) v2.8.1
|
|
||||||
- Storage Plugin
|
|
||||||
- [cephfs-provisioner](https://github.com/kubernetes-incubator/external-storage) v2.1.0-k8s1.11
|
|
||||||
- [rbd-provisioner](https://github.com/kubernetes-incubator/external-storage) v2.1.1-k8s1.11
|
|
||||||
- [aws-ebs-csi-plugin](https://github.com/kubernetes-sigs/aws-ebs-csi-driver) v0.5.0
|
|
||||||
- [azure-csi-plugin](https://github.com/kubernetes-sigs/azuredisk-csi-driver) v1.10.0
|
|
||||||
- [cinder-csi-plugin](https://github.com/kubernetes/cloud-provider-openstack/blob/master/docs/cinder-csi-plugin/using-cinder-csi-plugin.md) v1.22.0
|
|
||||||
- [gcp-pd-csi-plugin](https://github.com/kubernetes-sigs/gcp-compute-persistent-disk-csi-driver) v1.4.0
|
|
||||||
- [local-path-provisioner](https://github.com/rancher/local-path-provisioner) v0.0.22
|
|
||||||
- [local-volume-provisioner](https://github.com/kubernetes-sigs/sig-storage-local-static-provisioner) v2.5.0
|
|
||||||
|
|
||||||
## Container Runtime Notes
|
|
||||||
|
|
||||||
- The list of available docker version is 18.09, 19.03 and 20.10. The recommended docker version is 20.10. 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).
|
|
||||||
- The cri-o version should be aligned with the respective kubernetes version (i.e. kube_version=1.20.x, crio_version=1.20)
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
- **Minimum required version of Kubernetes is v1.23**
|
|
||||||
- **Ansible v2.11+, 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](docs/offline-environment.md))
|
|
||||||
- The target servers are configured to allow **IPv4 forwarding**.
|
|
||||||
- If using IPv6 for pods and services, the target servers are configured to allow **IPv6 forwarding**.
|
|
||||||
- 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.
|
|
||||||
- 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
|
|
||||||
or command parameters `--become or -b` should be specified.
|
|
||||||
|
|
||||||
Hardware:
|
|
||||||
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
|
|
||||||
- Memory: 1500 MB
|
|
||||||
- Node
|
|
||||||
- Memory: 1024 MB
|
|
||||||
|
|
||||||
## Network Plugins
|
|
||||||
|
|
||||||
You can choose between 10 network plugins. (default: `calico`, except Vagrant uses `flannel`)
|
|
||||||
|
|
||||||
- [flannel](docs/flannel.md): gre/vxlan (layer 2) networking.
|
|
||||||
|
|
||||||
- [Calico](https://docs.projectcalico.org/latest/introduction/) is a networking and network policy provider. Calico supports a flexible set of networking options
|
|
||||||
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.
|
|
||||||
|
|
||||||
- [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.
|
|
||||||
|
|
||||||
- [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/)).
|
|
||||||
|
|
||||||
- [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
|
|
||||||
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).
|
|
||||||
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.
|
|
||||||
|
|
||||||
The choice is defined with the variable `kube_network_plugin`. There is also an
|
|
||||||
option to leverage built-in cloud provider networking instead.
|
|
||||||
See also [Network checker](docs/netcheck.md).
|
|
||||||
|
|
||||||
## Ingress Plugins
|
|
||||||
|
|
||||||
- [nginx](https://kubernetes.github.io/ingress-nginx): the NGINX Ingress Controller.
|
|
||||||
|
|
||||||
- [metallb](docs/metallb.md): the MetalLB bare-metal service LoadBalancer provider.
|
|
||||||
|
|
||||||
## Community docs and resources
|
|
||||||
|
|
||||||
- [kubernetes.io/docs/setup/production-environment/tools/kubespray/](https://kubernetes.io/docs/setup/production-environment/tools/kubespray/)
|
|
||||||
- [kubespray, monitoring and logging](https://github.com/gregbkr/kubernetes-kargo-logging-monitoring) by @gregbkr
|
|
||||||
- [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)
|
|
||||||
|
|
||||||
## Tools and projects on top of Kubespray
|
|
||||||
|
|
||||||
- [Digital Rebar Provision](https://github.com/digitalrebar/provision/blob/v4/doc/integrations/ansible.rst)
|
|
||||||
- [Terraform Contrib](https://github.com/kubernetes-sigs/kubespray/tree/master/contrib/terraform)
|
|
||||||
- [Kubean](https://github.com/kubean-io/kubean)
|
|
||||||
|
|
||||||
## CI Tests
|
|
||||||
|
|
||||||
[![Build graphs](https://gitlab.com/kargo-ci/kubernetes-sigs-kubespray/badges/master/pipeline.svg)](https://gitlab.com/kargo-ci/kubernetes-sigs-kubespray/pipelines)
|
|
||||||
|
|
||||||
CI/end-to-end tests sponsored by: [CNCF](https://cncf.io), [Equinix Metal](https://metal.equinix.com/), [OVHcloud](https://www.ovhcloud.com/), [ELASTX](https://elastx.se/).
|
|
||||||
|
|
||||||
See the [test matrix](docs/test_cases.md) for details.
|
|
||||||
|
|
83
RELEASE.md
83
RELEASE.md
|
@ -1,83 +0,0 @@
|
||||||
# Release Process
|
|
||||||
|
|
||||||
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. Please see [a good sample issue](https://github.com/kubernetes-sigs/kubespray/issues/8325)
|
|
||||||
2. At least one of the [approvers](OWNERS_ALIASES) must approve this release
|
|
||||||
3. The `kube_version_min_required` variable is set to `n-1`
|
|
||||||
4. Remove hashes for [EOL versions](https://github.com/kubernetes/website/blob/main/content/en/releases/patch-releases.md) of kubernetes from `*_checksums` variables.
|
|
||||||
5. Create the release note with [Kubernetes Release Notes Generator](https://github.com/kubernetes/release/blob/master/cmd/release-notes/README.md). See the following `Release note creation` section for the details.
|
|
||||||
6. 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
|
|
||||||
7. An approver creates a release branch in the form `release-X.Y`
|
|
||||||
8. 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) container images are built and tagged. See the following `Container image creation` section for the details.
|
|
||||||
9. The `KUBESPRAY_VERSION` variable is updated in `.gitlab-ci.yml`
|
|
||||||
10. The release issue is closed
|
|
||||||
11. An announcement email is sent to `dev@kubernetes.io` with the subject `[ANNOUNCE] Kubespray $VERSION is released`
|
|
||||||
12. The topic of the #kubespray channel is updated with `vX.Y.Z is released! | ...`
|
|
||||||
|
|
||||||
## Major/minor releases and milestones
|
|
||||||
|
|
||||||
* For major releases (vX.Y) Kubespray maintains one branch (`release-X.Y`). Minor releases (vX.Y.Z) are available only as tags.
|
|
||||||
|
|
||||||
* Security patches and bugs might be backported.
|
|
||||||
|
|
||||||
* 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
|
|
||||||
[GitHub milestone](https://github.com/kubernetes-sigs/kubespray/milestones).
|
|
||||||
That milestone remains open for the major/minor releases support lifetime,
|
|
||||||
which ends once the milestone is closed. Then only a next major or minor release
|
|
||||||
can be done.
|
|
||||||
|
|
||||||
* 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.
|
|
||||||
Older or newer component versions are not supported and not tested for the given
|
|
||||||
release (even if included in the checksum variables, like `kubeadm_checksums`).
|
|
||||||
|
|
||||||
* There is no unstable releases and no APIs, thus Kubespray doesn't follow
|
|
||||||
[semver](https://semver.org/). Every version describes only a stable release.
|
|
||||||
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
|
|
||||||
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
|
|
||||||
document.
|
|
||||||
|
|
||||||
* 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
|
|
||||||
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
|
|
||||||
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.
|
|
||||||
|
|
||||||
## Release note creation
|
|
||||||
|
|
||||||
You can create a release note with:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
export GITHUB_TOKEN=<your-github-token>
|
|
||||||
export ORG=kubernetes-sigs
|
|
||||||
export REPO=kubespray
|
|
||||||
release-notes --start-sha <The start commit-id> --end-sha <The end commit-id> --dependencies=false --output=/tmp/kubespray-release-note --required-author=""
|
|
||||||
```
|
|
||||||
|
|
||||||
If the release note file(/tmp/kubespray-release-note) contains "### Uncategorized" pull requests, those pull requests don't have a valid kind label(`kind/feature`, etc.).
|
|
||||||
It is necessary to put a valid label on each pull request and run the above release-notes command again to get a better release note)
|
|
||||||
|
|
||||||
## Container image creation
|
|
||||||
|
|
||||||
The container image `quay.io/kubespray/kubespray:vX.Y.Z` can be created from Dockerfile of the kubespray root directory:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cd kubespray/
|
|
||||||
nerdctl build -t quay.io/kubespray/kubespray:vX.Y.Z .
|
|
||||||
nerdctl push quay.io/kubespray/kubespray:vX.Y.Z
|
|
||||||
```
|
|
||||||
|
|
||||||
The container image `quay.io/kubespray/vagrant:vX.Y.Z` can be created from build.sh of test-infra/vagrant-docker/:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cd kubespray/test-infra/vagrant-docker/
|
|
||||||
./build vX.Y.Z
|
|
||||||
```
|
|
||||||
|
|
||||||
Please note that the above operation requires the permission to push container images into quay.io/kubespray/.
|
|
||||||
If you don't have the permission, please ask it on the #kubespray-dev channel.
|
|
|
@ -1,15 +0,0 @@
|
||||||
# Defined below are the security contacts for this repo.
|
|
||||||
#
|
|
||||||
# They are the contact point for the Product Security Committee to reach out
|
|
||||||
# to for triaging and handling of incoming issues.
|
|
||||||
#
|
|
||||||
# The below names agree to abide by the
|
|
||||||
# [Embargo Policy](https://git.k8s.io/security/private-distributors-list.md#embargo-policy)
|
|
||||||
# and will be removed and replaced if they violate that agreement.
|
|
||||||
#
|
|
||||||
# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE
|
|
||||||
# INSTRUCTIONS AT https://kubernetes.io/security/
|
|
||||||
mattymo
|
|
||||||
floryut
|
|
||||||
oomichi
|
|
||||||
cristicalin
|
|
275
Vagrantfile
vendored
275
Vagrantfile
vendored
|
@ -1,275 +0,0 @@
|
||||||
# -*- mode: ruby -*-
|
|
||||||
# # vi: set ft=ruby :
|
|
||||||
|
|
||||||
# For help on using kubespray with vagrant, check out docs/vagrant.md
|
|
||||||
|
|
||||||
require 'fileutils'
|
|
||||||
|
|
||||||
Vagrant.require_version ">= 2.0.0"
|
|
||||||
|
|
||||||
CONFIG = File.join(File.dirname(__FILE__), ENV['KUBESPRAY_VAGRANT_CONFIG'] || 'vagrant/config.rb')
|
|
||||||
|
|
||||||
FLATCAR_URL_TEMPLATE = "https://%s.release.flatcar-linux.net/amd64-usr/current/flatcar_production_vagrant.json"
|
|
||||||
|
|
||||||
# Uniq disk UUID for libvirt
|
|
||||||
DISK_UUID = Time.now.utc.to_i
|
|
||||||
|
|
||||||
SUPPORTED_OS = {
|
|
||||||
"flatcar-stable" => {box: "flatcar-stable", user: "core", box_url: FLATCAR_URL_TEMPLATE % ["stable"]},
|
|
||||||
"flatcar-beta" => {box: "flatcar-beta", user: "core", box_url: FLATCAR_URL_TEMPLATE % ["beta"]},
|
|
||||||
"flatcar-alpha" => {box: "flatcar-alpha", user: "core", box_url: FLATCAR_URL_TEMPLATE % ["alpha"]},
|
|
||||||
"flatcar-edge" => {box: "flatcar-edge", user: "core", box_url: FLATCAR_URL_TEMPLATE % ["edge"]},
|
|
||||||
"ubuntu1604" => {box: "generic/ubuntu1604", user: "vagrant"},
|
|
||||||
"ubuntu1804" => {box: "generic/ubuntu1804", user: "vagrant"},
|
|
||||||
"ubuntu2004" => {box: "generic/ubuntu2004", 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"},
|
|
||||||
"almalinux8" => {box: "almalinux/8", user: "vagrant"},
|
|
||||||
"almalinux8-bento" => {box: "bento/almalinux-8", user: "vagrant"},
|
|
||||||
"rockylinux8" => {box: "generic/rocky8", user: "vagrant"},
|
|
||||||
"fedora35" => {box: "fedora/35-cloud-base", user: "vagrant"},
|
|
||||||
"fedora36" => {box: "fedora/36-cloud-base", user: "vagrant"},
|
|
||||||
"opensuse" => {box: "opensuse/Leap-15.4.x86_64", user: "vagrant"},
|
|
||||||
"opensuse-tumbleweed" => {box: "opensuse/Tumbleweed.x86_64", user: "vagrant"},
|
|
||||||
"oraclelinux" => {box: "generic/oracle7", user: "vagrant"},
|
|
||||||
"oraclelinux8" => {box: "generic/oracle8", user: "vagrant"},
|
|
||||||
"rhel7" => {box: "generic/rhel7", user: "vagrant"},
|
|
||||||
"rhel8" => {box: "generic/rhel8", user: "vagrant"},
|
|
||||||
}
|
|
||||||
|
|
||||||
if File.exist?(CONFIG)
|
|
||||||
require CONFIG
|
|
||||||
end
|
|
||||||
|
|
||||||
# Defaults for config options defined in CONFIG
|
|
||||||
$num_instances ||= 3
|
|
||||||
$instance_name_prefix ||= "k8s"
|
|
||||||
$vm_gui ||= false
|
|
||||||
$vm_memory ||= 2048
|
|
||||||
$vm_cpus ||= 2
|
|
||||||
$shared_folders ||= {}
|
|
||||||
$forwarded_ports ||= {}
|
|
||||||
$subnet ||= "172.18.8"
|
|
||||||
$subnet_ipv6 ||= "fd3c:b398:0698:0756"
|
|
||||||
$os ||= "ubuntu1804"
|
|
||||||
$network_plugin ||= "flannel"
|
|
||||||
# Setting multi_networking to true will install Multus: https://github.com/intel/multus-cni
|
|
||||||
$multi_networking ||= "False"
|
|
||||||
$download_run_once ||= "True"
|
|
||||||
$download_force_cache ||= "False"
|
|
||||||
# The first three nodes are etcd servers
|
|
||||||
$etcd_instances ||= $num_instances
|
|
||||||
# The first two nodes are kube masters
|
|
||||||
$kube_master_instances ||= $num_instances == 1 ? $num_instances : ($num_instances - 1)
|
|
||||||
# All nodes are kube nodes
|
|
||||||
$kube_node_instances ||= $num_instances
|
|
||||||
# The following only works when using the libvirt provider
|
|
||||||
$kube_node_instances_with_disks ||= false
|
|
||||||
$kube_node_instances_with_disks_size ||= "20G"
|
|
||||||
$kube_node_instances_with_disks_number ||= 2
|
|
||||||
$override_disk_size ||= false
|
|
||||||
$disk_size ||= "20GB"
|
|
||||||
$local_path_provisioner_enabled ||= "False"
|
|
||||||
$local_path_provisioner_claim_root ||= "/opt/local-path-provisioner/"
|
|
||||||
$libvirt_nested ||= false
|
|
||||||
# boolean or string (e.g. "-vvv")
|
|
||||||
$ansible_verbosity ||= false
|
|
||||||
$ansible_tags ||= ENV['VAGRANT_ANSIBLE_TAGS'] || ""
|
|
||||||
|
|
||||||
$playbook ||= "cluster.yml"
|
|
||||||
|
|
||||||
host_vars = {}
|
|
||||||
|
|
||||||
$box = SUPPORTED_OS[$os][:box]
|
|
||||||
# if $inventory is not set, try to use example
|
|
||||||
$inventory = "inventory/sample" if ! $inventory
|
|
||||||
$inventory = File.absolute_path($inventory, File.dirname(__FILE__))
|
|
||||||
|
|
||||||
# if $inventory has a hosts.ini file use it, otherwise copy over
|
|
||||||
# vars etc to where vagrant expects dynamic inventory to be
|
|
||||||
if ! File.exist?(File.join(File.dirname($inventory), "hosts.ini"))
|
|
||||||
$vagrant_ansible = File.join(File.dirname(__FILE__), ".vagrant", "provisioners", "ansible")
|
|
||||||
FileUtils.mkdir_p($vagrant_ansible) if ! File.exist?($vagrant_ansible)
|
|
||||||
$vagrant_inventory = File.join($vagrant_ansible,"inventory")
|
|
||||||
FileUtils.rm_f($vagrant_inventory)
|
|
||||||
FileUtils.ln_s($inventory, $vagrant_inventory)
|
|
||||||
end
|
|
||||||
|
|
||||||
if Vagrant.has_plugin?("vagrant-proxyconf")
|
|
||||||
$no_proxy = ENV['NO_PROXY'] || ENV['no_proxy'] || "127.0.0.1,localhost"
|
|
||||||
(1..$num_instances).each do |i|
|
|
||||||
$no_proxy += ",#{$subnet}.#{i+100}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Vagrant.configure("2") do |config|
|
|
||||||
|
|
||||||
config.vm.box = $box
|
|
||||||
if SUPPORTED_OS[$os].has_key? :box_url
|
|
||||||
config.vm.box_url = SUPPORTED_OS[$os][:box_url]
|
|
||||||
end
|
|
||||||
config.ssh.username = SUPPORTED_OS[$os][:user]
|
|
||||||
|
|
||||||
# plugin conflict
|
|
||||||
if Vagrant.has_plugin?("vagrant-vbguest") then
|
|
||||||
config.vbguest.auto_update = false
|
|
||||||
end
|
|
||||||
|
|
||||||
# always use Vagrants insecure key
|
|
||||||
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|
|
|
||||||
config.vm.define vm_name = "%s-%01d" % [$instance_name_prefix, i] do |node|
|
|
||||||
|
|
||||||
node.vm.hostname = vm_name
|
|
||||||
|
|
||||||
if Vagrant.has_plugin?("vagrant-proxyconf")
|
|
||||||
node.proxy.http = ENV['HTTP_PROXY'] || ENV['http_proxy'] || ""
|
|
||||||
node.proxy.https = ENV['HTTPS_PROXY'] || ENV['https_proxy'] || ""
|
|
||||||
node.proxy.no_proxy = $no_proxy
|
|
||||||
end
|
|
||||||
|
|
||||||
["vmware_fusion", "vmware_workstation"].each do |vmware|
|
|
||||||
node.vm.provider vmware do |v|
|
|
||||||
v.vmx['memsize'] = $vm_memory
|
|
||||||
v.vmx['numvcpus'] = $vm_cpus
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
node.vm.provider :virtualbox do |vb|
|
|
||||||
vb.memory = $vm_memory
|
|
||||||
vb.cpus = $vm_cpus
|
|
||||||
vb.gui = $vm_gui
|
|
||||||
vb.linked_clone = true
|
|
||||||
vb.customize ["modifyvm", :id, "--vram", "8"] # ubuntu defaults to 256 MB which is a waste of precious RAM
|
|
||||||
vb.customize ["modifyvm", :id, "--audio", "none"]
|
|
||||||
end
|
|
||||||
|
|
||||||
node.vm.provider :libvirt do |lv|
|
|
||||||
lv.nested = $libvirt_nested
|
|
||||||
lv.cpu_mode = "host-model"
|
|
||||||
lv.memory = $vm_memory
|
|
||||||
lv.cpus = $vm_cpus
|
|
||||||
lv.default_prefix = 'kubespray'
|
|
||||||
# Fix kernel panic on fedora 28
|
|
||||||
if $os == "fedora"
|
|
||||||
lv.cpu_mode = "host-passthrough"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if $kube_node_instances_with_disks
|
|
||||||
# Libvirt
|
|
||||||
driverletters = ('a'..'z').to_a
|
|
||||||
node.vm.provider :libvirt do |lv|
|
|
||||||
# always make /dev/sd{a/b/c} so that CI can ensure that
|
|
||||||
# virtualbox and libvirt will have the same devices to use for OSDs
|
|
||||||
(1..$kube_node_instances_with_disks_number).each do |d|
|
|
||||||
lv.storage :file, :device => "hd#{driverletters[d]}", :path => "disk-#{i}-#{d}-#{DISK_UUID}.disk", :size => $kube_node_instances_with_disks_size, :bus => "scsi"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if $expose_docker_tcp
|
|
||||||
node.vm.network "forwarded_port", guest: 2375, host: ($expose_docker_tcp + i - 1), auto_correct: true
|
|
||||||
end
|
|
||||||
|
|
||||||
$forwarded_ports.each do |guest, host|
|
|
||||||
node.vm.network "forwarded_port", guest: guest, host: host, auto_correct: true
|
|
||||||
end
|
|
||||||
|
|
||||||
if ["rhel7","rhel8"].include? $os
|
|
||||||
# Vagrant synced_folder rsync options cannot be used for RHEL boxes as Rsync package cannot
|
|
||||||
# be installed until the host is registered with a valid Red Hat support subscription
|
|
||||||
node.vm.synced_folder ".", "/vagrant", disabled: false
|
|
||||||
$shared_folders.each do |src, dst|
|
|
||||||
node.vm.synced_folder src, dst
|
|
||||||
end
|
|
||||||
else
|
|
||||||
node.vm.synced_folder ".", "/vagrant", disabled: false, type: "rsync", rsync__args: ['--verbose', '--archive', '--delete', '-z'] , rsync__exclude: ['.git','venv']
|
|
||||||
$shared_folders.each do |src, dst|
|
|
||||||
node.vm.synced_folder src, dst, type: "rsync", rsync__args: ['--verbose', '--archive', '--delete', '-z']
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
ip = "#{$subnet}.#{i+100}"
|
|
||||||
node.vm.network :private_network, ip: ip,
|
|
||||||
:libvirt__guest_ipv6 => 'yes',
|
|
||||||
:libvirt__ipv6_address => "#{$subnet_ipv6}::#{i+100}",
|
|
||||||
:libvirt__ipv6_prefix => "64",
|
|
||||||
:libvirt__forward_mode => "none",
|
|
||||||
:libvirt__dhcp_enabled => false
|
|
||||||
|
|
||||||
# Disable swap for each vm
|
|
||||||
node.vm.provision "shell", inline: "swapoff -a"
|
|
||||||
|
|
||||||
# ubuntu1804 and ubuntu2004 have IPv6 explicitly disabled. This undoes that.
|
|
||||||
if ["ubuntu1804", "ubuntu2004"].include? $os
|
|
||||||
node.vm.provision "shell", inline: "rm -f /etc/modprobe.d/local.conf"
|
|
||||||
node.vm.provision "shell", inline: "sed -i '/net.ipv6.conf.all.disable_ipv6/d' /etc/sysctl.d/99-sysctl.conf /etc/sysctl.conf"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Disable firewalld on oraclelinux/redhat vms
|
|
||||||
if ["oraclelinux","oraclelinux8","rhel7","rhel8"].include? $os
|
|
||||||
node.vm.provision "shell", inline: "systemctl stop firewalld; systemctl disable firewalld"
|
|
||||||
end
|
|
||||||
|
|
||||||
host_vars[vm_name] = {
|
|
||||||
"ip": ip,
|
|
||||||
"flannel_interface": "eth1",
|
|
||||||
"kube_network_plugin": $network_plugin,
|
|
||||||
"kube_network_plugin_multus": $multi_networking,
|
|
||||||
"download_run_once": $download_run_once,
|
|
||||||
"download_localhost": "False",
|
|
||||||
"download_cache_dir": ENV['HOME'] + "/kubespray_cache",
|
|
||||||
# Make kubespray cache even when download_run_once is false
|
|
||||||
"download_force_cache": $download_force_cache,
|
|
||||||
# Keeping the cache on the nodes can improve provisioning speed while debugging kubespray
|
|
||||||
"download_keep_remote_cache": "False",
|
|
||||||
"docker_rpm_keepcache": "1",
|
|
||||||
# These two settings will put kubectl and admin.config in $inventory/artifacts
|
|
||||||
"kubeconfig_localhost": "True",
|
|
||||||
"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.
|
|
||||||
# And limit the action to gathering facts, the full playbook is going to be ran by testcases_run.sh
|
|
||||||
if i == $num_instances
|
|
||||||
node.vm.provision "ansible" do |ansible|
|
|
||||||
ansible.playbook = $playbook
|
|
||||||
ansible.verbose = $ansible_verbosity
|
|
||||||
$ansible_inventory_path = File.join( $inventory, "hosts.ini")
|
|
||||||
if File.exist?($ansible_inventory_path)
|
|
||||||
ansible.inventory_path = $ansible_inventory_path
|
|
||||||
end
|
|
||||||
ansible.become = true
|
|
||||||
ansible.limit = "all,localhost"
|
|
||||||
ansible.host_key_checking = false
|
|
||||||
ansible.raw_arguments = ["--forks=#{$num_instances}", "--flush-cache", "-e ansible_become_pass=vagrant"]
|
|
||||||
ansible.host_vars = host_vars
|
|
||||||
if $ansible_tags != ""
|
|
||||||
ansible.tags = [$ansible_tags]
|
|
||||||
end
|
|
||||||
ansible.groups = {
|
|
||||||
"etcd" => ["#{$instance_name_prefix}-[1:#{$etcd_instances}]"],
|
|
||||||
"kube_control_plane" => ["#{$instance_name_prefix}-[1:#{$kube_master_instances}]"],
|
|
||||||
"kube_node" => ["#{$instance_name_prefix}-[1:#{$kube_node_instances}]"],
|
|
||||||
"k8s_cluster:children" => ["kube_control_plane", "kube_node"],
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,2 +0,0 @@
|
||||||
---
|
|
||||||
theme: jekyll-theme-slate
|
|
18
ansible.cfg
18
ansible.cfg
|
@ -1,22 +1,4 @@
|
||||||
[ssh_connection]
|
[ssh_connection]
|
||||||
pipelining=True
|
pipelining=True
|
||||||
ansible_ssh_args = -o ControlMaster=auto -o ControlPersist=30m -o ConnectionAttempts=100 -o UserKnownHostsFile=/dev/null
|
|
||||||
#control_path = ~/.ssh/ansible-%%r@%%h:%%p
|
|
||||||
[defaults]
|
[defaults]
|
||||||
# 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
|
|
||||||
fact_caching = jsonfile
|
|
||||||
fact_caching_connection = /tmp
|
|
||||||
fact_caching_timeout = 86400
|
|
||||||
stdout_callback = default
|
|
||||||
display_skipped_hosts = no
|
|
||||||
library = ./library
|
|
||||||
callbacks_enabled = profile_tasks,ara_default
|
|
||||||
roles_path = roles:$VIRTUAL_ENV/usr/local/share/kubespray/roles:$VIRTUAL_ENV/usr/local/share/ansible/roles:/usr/share/kubespray/roles
|
|
||||||
deprecation_warnings=False
|
|
||||||
inventory_ignore_extensions = ~, .orig, .bak, .ini, .cfg, .retry, .pyc, .pyo, .creds, .gpg
|
|
||||||
[inventory]
|
|
||||||
ignore_patterns = artifacts, credentials
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
---
|
|
||||||
- hosts: localhost
|
|
||||||
gather_facts: false
|
|
||||||
become: no
|
|
||||||
vars:
|
|
||||||
minimal_ansible_version: 2.11.0
|
|
||||||
maximal_ansible_version: 2.14.0
|
|
||||||
ansible_connection: local
|
|
||||||
tags: always
|
|
||||||
tasks:
|
|
||||||
- name: "Check {{ minimal_ansible_version }} <= Ansible version < {{ maximal_ansible_version }}"
|
|
||||||
assert:
|
|
||||||
msg: "Ansible must be between {{ minimal_ansible_version }} and {{ maximal_ansible_version }} exclusive"
|
|
||||||
that:
|
|
||||||
- ansible_version.string is version(minimal_ansible_version, ">=")
|
|
||||||
- ansible_version.string is version(maximal_ansible_version, "<")
|
|
||||||
tags:
|
|
||||||
- check
|
|
||||||
|
|
||||||
- name: "Check that python netaddr is installed"
|
|
||||||
assert:
|
|
||||||
msg: "Python netaddr is not present"
|
|
||||||
that: "'127.0.0.1' | ipaddr"
|
|
||||||
tags:
|
|
||||||
- check
|
|
||||||
|
|
||||||
# CentOS 7 provides too old jinja version
|
|
||||||
- name: "Check that jinja is not too old (install via pip)"
|
|
||||||
assert:
|
|
||||||
msg: "Your Jinja version is too old, install via pip"
|
|
||||||
that: "{% set test %}It works{% endset %}{{ test == 'It works' }}"
|
|
||||||
tags:
|
|
||||||
- check
|
|
131
cluster.yml
131
cluster.yml
|
@ -1,131 +1,18 @@
|
||||||
---
|
---
|
||||||
- name: Check ansible version
|
- hosts: k8s-cluster
|
||||||
import_playbook: ansible_version.yml
|
|
||||||
|
|
||||||
- name: Ensure compatibility with old groups
|
|
||||||
import_playbook: legacy_groups.yml
|
|
||||||
|
|
||||||
- hosts: bastion[0]
|
|
||||||
gather_facts: False
|
|
||||||
environment: "{{ proxy_disable_env }}"
|
|
||||||
roles:
|
roles:
|
||||||
- { role: kubespray-defaults }
|
- { role: adduser, tags: adduser }
|
||||||
- { role: bastion-ssh-config, tags: ["localhost", "bastion"] }
|
- { role: download, tags: download }
|
||||||
|
|
||||||
- hosts: k8s_cluster:etcd
|
|
||||||
strategy: linear
|
|
||||||
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
|
|
||||||
gather_facts: false
|
|
||||||
environment: "{{ proxy_disable_env }}"
|
|
||||||
roles:
|
|
||||||
- { role: kubespray-defaults }
|
|
||||||
- { role: bootstrap-os, tags: bootstrap-os}
|
|
||||||
|
|
||||||
- name: Gather facts
|
|
||||||
tags: always
|
|
||||||
import_playbook: facts.yml
|
|
||||||
|
|
||||||
- hosts: k8s_cluster:etcd
|
|
||||||
gather_facts: False
|
|
||||||
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
|
|
||||||
environment: "{{ proxy_disable_env }}"
|
|
||||||
roles:
|
|
||||||
- { role: kubespray-defaults }
|
|
||||||
- { role: kubernetes/preinstall, tags: preinstall }
|
- { role: kubernetes/preinstall, tags: preinstall }
|
||||||
- { role: "container-engine", tags: "container-engine", when: deploy_container_engine }
|
- { role: etcd, tags: etcd }
|
||||||
- { role: download, tags: download, when: "not skip_downloads" }
|
- { role: docker, tags: docker, when: ansible_os_family != "CoreOS" }
|
||||||
|
|
||||||
- hosts: etcd:kube_control_plane
|
|
||||||
gather_facts: False
|
|
||||||
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
|
|
||||||
environment: "{{ proxy_disable_env }}"
|
|
||||||
roles:
|
|
||||||
- { role: kubespray-defaults }
|
|
||||||
- role: etcd
|
|
||||||
tags: etcd
|
|
||||||
vars:
|
|
||||||
etcd_cluster_setup: true
|
|
||||||
etcd_events_cluster_setup: "{{ etcd_events_cluster_enabled }}"
|
|
||||||
when: etcd_deployment_type != "kubeadm"
|
|
||||||
|
|
||||||
- hosts: k8s_cluster
|
|
||||||
gather_facts: False
|
|
||||||
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
|
|
||||||
environment: "{{ proxy_disable_env }}"
|
|
||||||
roles:
|
|
||||||
- { role: kubespray-defaults }
|
|
||||||
- role: etcd
|
|
||||||
tags: etcd
|
|
||||||
vars:
|
|
||||||
etcd_cluster_setup: false
|
|
||||||
etcd_events_cluster_setup: false
|
|
||||||
when:
|
|
||||||
- etcd_deployment_type != "kubeadm"
|
|
||||||
- kube_network_plugin in ["calico", "flannel", "canal", "cilium"] or cilium_deploy_additionally | default(false) | bool
|
|
||||||
- kube_network_plugin != "calico" or calico_datastore == "etcd"
|
|
||||||
|
|
||||||
- hosts: k8s_cluster
|
|
||||||
gather_facts: False
|
|
||||||
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
|
|
||||||
environment: "{{ proxy_disable_env }}"
|
|
||||||
roles:
|
|
||||||
- { role: kubespray-defaults }
|
|
||||||
- { role: kubernetes/node, tags: node }
|
- { role: kubernetes/node, tags: node }
|
||||||
|
|
||||||
- hosts: kube_control_plane
|
|
||||||
gather_facts: False
|
|
||||||
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
|
|
||||||
environment: "{{ proxy_disable_env }}"
|
|
||||||
roles:
|
|
||||||
- { role: kubespray-defaults }
|
|
||||||
- { role: kubernetes/control-plane, tags: master }
|
|
||||||
- { role: kubernetes/client, tags: client }
|
|
||||||
- { role: kubernetes-apps/cluster_roles, tags: cluster-roles }
|
|
||||||
|
|
||||||
- hosts: k8s_cluster
|
|
||||||
gather_facts: False
|
|
||||||
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
|
|
||||||
environment: "{{ proxy_disable_env }}"
|
|
||||||
roles:
|
|
||||||
- { role: kubespray-defaults }
|
|
||||||
- { role: kubernetes/kubeadm, tags: kubeadm}
|
|
||||||
- { role: kubernetes/node-label, tags: node-label }
|
|
||||||
- { role: network_plugin, tags: network }
|
- { role: network_plugin, tags: network }
|
||||||
|
|
||||||
- hosts: calico_rr
|
- hosts: kube-master
|
||||||
gather_facts: False
|
|
||||||
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
|
|
||||||
environment: "{{ proxy_disable_env }}"
|
|
||||||
roles:
|
roles:
|
||||||
- { role: kubespray-defaults }
|
- { role: kubernetes/master, tags: master }
|
||||||
- { role: network_plugin/calico/rr, tags: ['network', 'calico_rr'] }
|
|
||||||
|
|
||||||
- hosts: kube_control_plane[0]
|
- hosts: k8s-cluster
|
||||||
gather_facts: False
|
|
||||||
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
|
|
||||||
environment: "{{ proxy_disable_env }}"
|
|
||||||
roles:
|
roles:
|
||||||
- { role: kubespray-defaults }
|
- { role: dnsmasq, tags: dnsmasq }
|
||||||
- { role: win_nodes/kubernetes_patch, tags: ["master", "win_nodes"] }
|
|
||||||
|
|
||||||
- hosts: kube_control_plane
|
|
||||||
gather_facts: False
|
|
||||||
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
|
|
||||||
environment: "{{ proxy_disable_env }}"
|
|
||||||
roles:
|
|
||||||
- { role: kubespray-defaults }
|
|
||||||
- { role: kubernetes-apps/external_cloud_controller, tags: external-cloud-controller }
|
|
||||||
- { role: kubernetes-apps/network_plugin, tags: network }
|
|
||||||
- { role: kubernetes-apps/policy_controller, tags: policy-controller }
|
|
||||||
- { role: kubernetes-apps/ingress_controller, tags: ingress-controller }
|
|
||||||
- { role: kubernetes-apps/external_provisioner, tags: external-provisioner }
|
|
||||||
- { role: kubernetes-apps, tags: apps }
|
|
||||||
|
|
||||||
- name: Apply resolv.conf changes now that cluster DNS is up
|
|
||||||
hosts: k8s_cluster
|
|
||||||
gather_facts: False
|
|
||||||
any_errors_fatal: "{{ any_errors_fatal | default(true) }}"
|
|
||||||
environment: "{{ proxy_disable_env }}"
|
|
||||||
roles:
|
|
||||||
- { role: kubespray-defaults }
|
|
||||||
- { role: kubernetes/preinstall, when: "dns_mode != 'none' and resolvconf_mode == 'host_resolvconf'", tags: resolvconf, dns_late: true }
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
# Kubernetes Community Code of Conduct
|
|
||||||
|
|
||||||
Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md)
|
|
|
@ -1,27 +0,0 @@
|
||||||
{
|
|
||||||
"Version": "2012-10-17",
|
|
||||||
"Statement": [
|
|
||||||
{
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Action": ["ec2:*"],
|
|
||||||
"Resource": ["*"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Action": ["elasticloadbalancing:*"],
|
|
||||||
"Resource": ["*"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Action": ["route53:*"],
|
|
||||||
"Resource": ["*"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Action": "s3:*",
|
|
||||||
"Resource": [
|
|
||||||
"arn:aws:s3:::kubernetes-*"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"Version": "2012-10-17",
|
|
||||||
"Statement": [
|
|
||||||
{
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Principal": { "Service": "ec2.amazonaws.com"},
|
|
||||||
"Action": "sts:AssumeRole"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
{
|
|
||||||
"Version": "2012-10-17",
|
|
||||||
"Statement": [
|
|
||||||
{
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Action": "s3:*",
|
|
||||||
"Resource": [
|
|
||||||
"arn:aws:s3:::kubernetes-*"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Action": "ec2:Describe*",
|
|
||||||
"Resource": "*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Action": "ec2:AttachVolume",
|
|
||||||
"Resource": "*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Action": "ec2:DetachVolume",
|
|
||||||
"Resource": "*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Action": ["route53:*"],
|
|
||||||
"Resource": ["*"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Action": [
|
|
||||||
"ecr:GetAuthorizationToken",
|
|
||||||
"ecr:BatchCheckLayerAvailability",
|
|
||||||
"ecr:GetDownloadUrlForLayer",
|
|
||||||
"ecr:GetRepositoryPolicy",
|
|
||||||
"ecr:DescribeRepositories",
|
|
||||||
"ecr:ListImages",
|
|
||||||
"ecr:BatchGetImage"
|
|
||||||
],
|
|
||||||
"Resource": "*"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
{
|
|
||||||
"Version": "2012-10-17",
|
|
||||||
"Statement": [
|
|
||||||
{
|
|
||||||
"Effect": "Allow",
|
|
||||||
"Principal": { "Service": "ec2.amazonaws.com"},
|
|
||||||
"Action": "sts:AssumeRole"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,76 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
import boto3
|
|
||||||
import os
|
|
||||||
import argparse
|
|
||||||
import json
|
|
||||||
|
|
||||||
class SearchEC2Tags(object):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.parse_args()
|
|
||||||
if self.args.list:
|
|
||||||
self.search_tags()
|
|
||||||
if self.args.host:
|
|
||||||
data = {}
|
|
||||||
print(json.dumps(data, indent=2))
|
|
||||||
|
|
||||||
def parse_args(self):
|
|
||||||
|
|
||||||
##Check if VPC_VISIBILITY is set, if not default to private
|
|
||||||
if "VPC_VISIBILITY" in os.environ:
|
|
||||||
self.vpc_visibility = os.environ['VPC_VISIBILITY']
|
|
||||||
else:
|
|
||||||
self.vpc_visibility = "private"
|
|
||||||
|
|
||||||
##Support --list and --host flags. We largely ignore the host one.
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
parser.add_argument('--list', action='store_true', default=False, help='List instances')
|
|
||||||
parser.add_argument('--host', action='store_true', help='Get all the variables about a specific instance')
|
|
||||||
self.args = parser.parse_args()
|
|
||||||
|
|
||||||
def search_tags(self):
|
|
||||||
hosts = {}
|
|
||||||
hosts['_meta'] = { 'hostvars': {} }
|
|
||||||
|
|
||||||
##Search ec2 three times to find nodes of each group type. Relies on kubespray-role key/value.
|
|
||||||
for group in ["kube_control_plane", "kube_node", "etcd"]:
|
|
||||||
hosts[group] = []
|
|
||||||
tag_key = "kubespray-role"
|
|
||||||
tag_value = ["*"+group+"*"]
|
|
||||||
region = os.environ['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')
|
|
||||||
if cluster_name:
|
|
||||||
filters.append({'Name': 'tag-key', 'Values': ['kubernetes.io/cluster/'+cluster_name]})
|
|
||||||
instances = ec2.instances.filter(Filters=filters)
|
|
||||||
for instance in instances:
|
|
||||||
|
|
||||||
##Suppose default vpc_visibility is private
|
|
||||||
dns_name = instance.private_dns_name
|
|
||||||
ansible_host = {
|
|
||||||
'ansible_ssh_host': instance.private_ip_address
|
|
||||||
}
|
|
||||||
|
|
||||||
##Override when vpc_visibility actually is public
|
|
||||||
if self.vpc_visibility == "public":
|
|
||||||
dns_name = instance.public_dns_name
|
|
||||||
ansible_host = {
|
|
||||||
'ansible_ssh_host': instance.public_ip_address
|
|
||||||
}
|
|
||||||
|
|
||||||
##Set when instance actually has node_labels
|
|
||||||
node_labels_tag = list(filter(lambda t: t['Key'] == 'kubespray-node-labels', instance.tags))
|
|
||||||
if node_labels_tag:
|
|
||||||
ansible_host['node_labels'] = dict([ label.strip().split('=') for label in node_labels_tag[0]['Value'].split(',') ])
|
|
||||||
|
|
||||||
hosts[group].append(dns_name)
|
|
||||||
hosts['_meta']['hostvars'][dns_name] = ansible_host
|
|
||||||
|
|
||||||
hosts['k8s_cluster'] = {'children':['kube_control_plane', 'kube_node']}
|
|
||||||
print(json.dumps(hosts, sort_keys=True, indent=2))
|
|
||||||
|
|
||||||
SearchEC2Tags()
|
|
|
@ -1 +0,0 @@
|
||||||
boto3 # Apache-2.0
|
|
2
contrib/azurerm/.gitignore
vendored
2
contrib/azurerm/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
||||||
.generated
|
|
||||||
/inventory
|
|
|
@ -1,67 +0,0 @@
|
||||||
# Kubernetes on Azure with Azure Resource Group Templates
|
|
||||||
|
|
||||||
Provision the base infrastructure for a Kubernetes cluster by using [Azure Resource Group Templates](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-authoring-templates)
|
|
||||||
|
|
||||||
## Status
|
|
||||||
|
|
||||||
This will provision the base infrastructure (vnet, vms, nics, ips, ...) needed for Kubernetes in Azure into the specified
|
|
||||||
Resource Group. It will not install Kubernetes itself, this has to be done in a later step by yourself (using kubespray of course).
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
- [Install azure-cli](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest)
|
|
||||||
- [Login with azure-cli](https://docs.microsoft.com/en-us/cli/azure/authenticate-azure-cli?view=azure-cli-latest)
|
|
||||||
- Dedicated Resource Group created in the Azure Portal or through azure-cli
|
|
||||||
|
|
||||||
## 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
|
|
||||||
unique due to some restrictions in Azure. The other one is the **ssh_public_keys** variable, it must be your ssh public
|
|
||||||
key to access your azure virtual machines. Most other variables should be self explanatory if you have some basic Kubernetes
|
|
||||||
experience.
|
|
||||||
|
|
||||||
## Bastion host
|
|
||||||
|
|
||||||
You can enable the use of a Bastion Host by changing **use_bastion** in group_vars/all to **true**. The generated
|
|
||||||
templates will then include an additional bastion VM which can then be used to connect to the masters and nodes. The option
|
|
||||||
also removes all public IPs from all other VMs.
|
|
||||||
|
|
||||||
## Generating and applying
|
|
||||||
|
|
||||||
To generate and apply the templates, call:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
./apply-rg.sh <resource_group_name>
|
|
||||||
```
|
|
||||||
|
|
||||||
If you change something in the configuration (e.g. number of nodes) later, you can call this again and Azure will
|
|
||||||
take care about creating/modifying whatever is needed.
|
|
||||||
|
|
||||||
## Clearing a resource group
|
|
||||||
|
|
||||||
If you need to delete all resources from a resource group, simply call:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
./clear-rg.sh <resource_group_name>
|
|
||||||
```
|
|
||||||
|
|
||||||
**WARNING** this really deletes everything from your resource group, including everything that was later created by you!
|
|
||||||
|
|
||||||
## Installing Ansible and the dependencies
|
|
||||||
|
|
||||||
Install Ansible according to [Ansible installation guide](/docs/ansible.md#installing-ansible)
|
|
||||||
|
|
||||||
## Generating an inventory for kubespray
|
|
||||||
|
|
||||||
After you have applied the templates, you can generate an inventory with this call:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
./generate-inventory.sh <resource_group_name>
|
|
||||||
```
|
|
||||||
|
|
||||||
It will create the file ./inventory which can then be used with kubespray, e.g.:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cd kubespray-root-dir
|
|
||||||
ansible-playbook -i contrib/azurerm/inventory -u devops --become -e "@inventory/sample/group_vars/all/all.yml" cluster.yml
|
|
||||||
```
|
|
|
@ -1,19 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
AZURE_RESOURCE_GROUP="$1"
|
|
||||||
|
|
||||||
if [ "$AZURE_RESOURCE_GROUP" == "" ]; then
|
|
||||||
echo "AZURE_RESOURCE_GROUP is missing"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
ansible-playbook generate-templates.yml
|
|
||||||
|
|
||||||
az deployment group create --template-file ./.generated/network.json -g $AZURE_RESOURCE_GROUP
|
|
||||||
az deployment group 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 deployment group create --template-file ./.generated/bastion.json -g $AZURE_RESOURCE_GROUP
|
|
||||||
az deployment group create --template-file ./.generated/masters.json -g $AZURE_RESOURCE_GROUP
|
|
||||||
az deployment group create --template-file ./.generated/minions.json -g $AZURE_RESOURCE_GROUP
|
|
|
@ -1,14 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
AZURE_RESOURCE_GROUP="$1"
|
|
||||||
|
|
||||||
if [ "$AZURE_RESOURCE_GROUP" == "" ]; then
|
|
||||||
echo "AZURE_RESOURCE_GROUP is missing"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
ansible-playbook generate-templates.yml
|
|
||||||
|
|
||||||
az group deployment create -g "$AZURE_RESOURCE_GROUP" --template-file ./.generated/clear-rg.json --mode Complete
|
|
|
@ -1,18 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
AZURE_RESOURCE_GROUP="$1"
|
|
||||||
|
|
||||||
if [ "$AZURE_RESOURCE_GROUP" == "" ]; then
|
|
||||||
echo "AZURE_RESOURCE_GROUP is missing"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
# check if azure cli 2.0 exists else use azure cli 1.0
|
|
||||||
if az &>/dev/null; then
|
|
||||||
ansible-playbook generate-inventory_2.yml -e azure_resource_group="$AZURE_RESOURCE_GROUP"
|
|
||||||
elif azure &>/dev/null; then
|
|
||||||
ansible-playbook generate-inventory.yml -e azure_resource_group="$AZURE_RESOURCE_GROUP"
|
|
||||||
else
|
|
||||||
echo "Azure cli not found"
|
|
||||||
fi
|
|
|
@ -1,5 +0,0 @@
|
||||||
---
|
|
||||||
- hosts: localhost
|
|
||||||
gather_facts: False
|
|
||||||
roles:
|
|
||||||
- generate-inventory
|
|
|
@ -1,5 +0,0 @@
|
||||||
---
|
|
||||||
- hosts: localhost
|
|
||||||
gather_facts: False
|
|
||||||
roles:
|
|
||||||
- generate-inventory_2
|
|
|
@ -1,5 +0,0 @@
|
||||||
---
|
|
||||||
- hosts: localhost
|
|
||||||
gather_facts: False
|
|
||||||
roles:
|
|
||||||
- generate-templates
|
|
|
@ -1,51 +0,0 @@
|
||||||
|
|
||||||
# Due to some Azure limitations (ex:- Storage Account's name must be unique),
|
|
||||||
# this name must be globally unique - it will be used as a prefix for azure components
|
|
||||||
cluster_name: example
|
|
||||||
|
|
||||||
# Set this to true if you do not want to have public IPs for your masters and minions. This will provision a bastion
|
|
||||||
# node that can be used to access the masters and minions
|
|
||||||
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.
|
|
||||||
# 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
|
|
||||||
|
|
||||||
number_of_k8s_masters: 3
|
|
||||||
number_of_k8s_nodes: 3
|
|
||||||
|
|
||||||
masters_vm_size: Standard_A2
|
|
||||||
masters_os_disk_size: 1000
|
|
||||||
|
|
||||||
minions_vm_size: Standard_A2
|
|
||||||
minions_os_disk_size: 1000
|
|
||||||
|
|
||||||
admin_username: devops
|
|
||||||
admin_password: changeme
|
|
||||||
|
|
||||||
# MAKE SURE TO CHANGE THIS TO YOUR PUBLIC KEY to access your azure machines
|
|
||||||
ssh_public_keys:
|
|
||||||
- "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLRzcxbsFDdEibiyXCSdIFh7bKbXso1NqlKjEyPTptf3aBXHEhVil0lJRjGpTlpfTy7PHvXFbXIOCdv9tOmeH1uxWDDeZawgPFV6VSZ1QneCL+8bxzhjiCn8133wBSPZkN8rbFKd9eEUUBfx8ipCblYblF9FcidylwtMt5TeEmXk8yRVkPiCuEYuDplhc2H0f4PsK3pFb5aDVdaDT3VeIypnOQZZoUxHWqm6ThyHrzLJd3SrZf+RROFWW1uInIDf/SZlXojczUYoffxgT1lERfOJCHJXsqbZWugbxQBwqsVsX59+KPxFFo6nV88h3UQr63wbFx52/MXkX4WrCkAHzN ablock-vwfs@dell-lappy"
|
|
||||||
|
|
||||||
# Disable using ssh using password. Change it to false to allow to connect to ssh by password
|
|
||||||
disablePasswordAuthentication: true
|
|
||||||
|
|
||||||
# Azure CIDRs
|
|
||||||
azure_vnet_cidr: 10.0.0.0/8
|
|
||||||
azure_admin_cidr: 10.241.2.0/24
|
|
||||||
azure_masters_cidr: 10.0.4.0/24
|
|
||||||
azure_minions_cidr: 10.240.0.0/16
|
|
||||||
|
|
||||||
# Azure loadbalancer port to use to access your cluster
|
|
||||||
kube_apiserver_port: 6443
|
|
||||||
|
|
||||||
# Azure Netwoking and storage naming to use with inventory/all.yml
|
|
||||||
#azure_virtual_network_name: KubeVNET
|
|
||||||
#azure_subnet_admin_name: ad-subnet
|
|
||||||
#azure_subnet_masters_name: master-subnet
|
|
||||||
#azure_subnet_minions_name: minion-subnet
|
|
||||||
#azure_route_table_name: routetable
|
|
||||||
#azure_security_group_name: secgroup
|
|
||||||
|
|
||||||
# Storage types available are: "Standard_LRS","Premium_LRS"
|
|
||||||
#azure_storage_account_type: Standard_LRS
|
|
|
@ -1,15 +0,0 @@
|
||||||
---
|
|
||||||
|
|
||||||
- name: Query Azure VMs # noqa 301
|
|
||||||
command: azure vm list-ip-address --json {{ azure_resource_group }}
|
|
||||||
register: vm_list_cmd
|
|
||||||
|
|
||||||
- name: Set vm_list
|
|
||||||
set_fact:
|
|
||||||
vm_list: "{{ vm_list_cmd.stdout }}"
|
|
||||||
|
|
||||||
- name: Generate inventory
|
|
||||||
template:
|
|
||||||
src: inventory.j2
|
|
||||||
dest: "{{ playbook_dir }}/inventory"
|
|
||||||
mode: 0644
|
|
|
@ -1,33 +0,0 @@
|
||||||
|
|
||||||
{% for vm in vm_list %}
|
|
||||||
{% if not use_bastion or vm.name == 'bastion' %}
|
|
||||||
{{ vm.name }} ansible_ssh_host={{ vm.networkProfile.networkInterfaces[0].expanded.ipConfigurations[0].publicIPAddress.expanded.ipAddress }} ip={{ vm.networkProfile.networkInterfaces[0].expanded.ipConfigurations[0].privateIPAddress }}
|
|
||||||
{% else %}
|
|
||||||
{{ vm.name }} ansible_ssh_host={{ vm.networkProfile.networkInterfaces[0].expanded.ipConfigurations[0].privateIPAddress }}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
[kube_control_plane]
|
|
||||||
{% for vm in vm_list %}
|
|
||||||
{% if 'kube_control_plane' in vm.tags.roles %}
|
|
||||||
{{ vm.name }}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
[etcd]
|
|
||||||
{% for vm in vm_list %}
|
|
||||||
{% if 'etcd' in vm.tags.roles %}
|
|
||||||
{{ vm.name }}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
[kube_node]
|
|
||||||
{% for vm in vm_list %}
|
|
||||||
{% if 'kube_node' in vm.tags.roles %}
|
|
||||||
{{ vm.name }}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
[k8s_cluster:children]
|
|
||||||
kube_node
|
|
||||||
kube_control_plane
|
|
|
@ -1,31 +0,0 @@
|
||||||
---
|
|
||||||
|
|
||||||
- name: Query Azure VMs IPs # noqa 301
|
|
||||||
command: az vm list-ip-addresses -o json --resource-group {{ azure_resource_group }}
|
|
||||||
register: vm_ip_list_cmd
|
|
||||||
|
|
||||||
- name: Query Azure VMs Roles # noqa 301
|
|
||||||
command: az vm list -o json --resource-group {{ azure_resource_group }}
|
|
||||||
register: vm_list_cmd
|
|
||||||
|
|
||||||
- name: Query Azure Load Balancer Public IP # noqa 301
|
|
||||||
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_roles_list: "{{ vm_list_cmd.stdout }}"
|
|
||||||
lb_pubip: "{{ lb_pubip_cmd.stdout }}"
|
|
||||||
|
|
||||||
- name: Generate inventory
|
|
||||||
template:
|
|
||||||
src: inventory.j2
|
|
||||||
dest: "{{ playbook_dir }}/inventory"
|
|
||||||
mode: 0644
|
|
||||||
|
|
||||||
- name: Generate Load Balancer variables
|
|
||||||
template:
|
|
||||||
src: loadbalancer_vars.j2
|
|
||||||
dest: "{{ playbook_dir }}/loadbalancer_vars.yml"
|
|
||||||
mode: 0644
|
|
|
@ -1,34 +0,0 @@
|
||||||
|
|
||||||
{% for vm in vm_ip_list %}
|
|
||||||
{% if not use_bastion or vm.virtualMachine.name == 'bastion' %}
|
|
||||||
{{ vm.virtualMachine.name }} ansible_ssh_host={{ vm.virtualMachine.network.publicIpAddresses[0].ipAddress }} ip={{ vm.virtualMachine.network.privateIpAddresses[0] }}
|
|
||||||
{% else %}
|
|
||||||
{{ vm.virtualMachine.name }} ansible_ssh_host={{ vm.virtualMachine.network.privateIpAddresses[0] }}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
[kube_control_plane]
|
|
||||||
{% for vm in vm_roles_list %}
|
|
||||||
{% if 'kube_control_plane' in vm.tags.roles %}
|
|
||||||
{{ vm.name }}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
[etcd]
|
|
||||||
{% for vm in vm_roles_list %}
|
|
||||||
{% if 'etcd' in vm.tags.roles %}
|
|
||||||
{{ vm.name }}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
[kube_node]
|
|
||||||
{% for vm in vm_roles_list %}
|
|
||||||
{% if 'kube_node' in vm.tags.roles %}
|
|
||||||
{{ vm.name }}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
[k8s_cluster:children]
|
|
||||||
kube_node
|
|
||||||
kube_control_plane
|
|
||||||
|
|
|
@ -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
|
|
|
@ -1,37 +0,0 @@
|
||||||
---
|
|
||||||
apiVersion: "2015-06-15"
|
|
||||||
|
|
||||||
virtualNetworkName: "{{ azure_virtual_network_name | default('KubeVNET') }}"
|
|
||||||
|
|
||||||
subnetAdminName: "{{ azure_subnet_admin_name | default('ad-subnet') }}"
|
|
||||||
subnetMastersName: "{{ azure_subnet_masters_name | default('master-subnet') }}"
|
|
||||||
subnetMinionsName: "{{ azure_subnet_minions_name | default('minion-subnet') }}"
|
|
||||||
|
|
||||||
routeTableName: "{{ azure_route_table_name | default('routetable') }}"
|
|
||||||
securityGroupName: "{{ azure_security_group_name | default('secgroup') }}"
|
|
||||||
|
|
||||||
nameSuffix: "{{ cluster_name }}"
|
|
||||||
|
|
||||||
availabilitySetMasters: "master-avs"
|
|
||||||
availabilitySetMinions: "minion-avs"
|
|
||||||
|
|
||||||
faultDomainCount: 3
|
|
||||||
updateDomainCount: 10
|
|
||||||
|
|
||||||
bastionVmSize: Standard_A0
|
|
||||||
bastionVMName: bastion
|
|
||||||
bastionIPAddressName: bastion-pubip
|
|
||||||
|
|
||||||
disablePasswordAuthentication: true
|
|
||||||
|
|
||||||
sshKeyPath: "/home/{{admin_username}}/.ssh/authorized_keys"
|
|
||||||
|
|
||||||
imageReference:
|
|
||||||
publisher: "OpenLogic"
|
|
||||||
offer: "CentOS"
|
|
||||||
sku: "7.5"
|
|
||||||
version: "latest"
|
|
||||||
imageReferenceJson: "{{imageReference|to_json}}"
|
|
||||||
|
|
||||||
storageAccountName: "sa{{nameSuffix | replace('-', '')}}"
|
|
||||||
storageAccountType: "{{ azure_storage_account_type | default('Standard_LRS') }}"
|
|
|
@ -1,25 +0,0 @@
|
||||||
---
|
|
||||||
- name: Set base_dir
|
|
||||||
set_fact:
|
|
||||||
base_dir: "{{ playbook_dir }}/.generated/"
|
|
||||||
|
|
||||||
- name: Create base_dir
|
|
||||||
file:
|
|
||||||
path: "{{ base_dir }}"
|
|
||||||
state: directory
|
|
||||||
recurse: true
|
|
||||||
mode: 0755
|
|
||||||
|
|
||||||
- name: Store json files in base_dir
|
|
||||||
template:
|
|
||||||
src: "{{ item }}"
|
|
||||||
dest: "{{ base_dir }}/{{ item }}"
|
|
||||||
mode: 0644
|
|
||||||
with_items:
|
|
||||||
- network.json
|
|
||||||
- storage.json
|
|
||||||
- availability-sets.json
|
|
||||||
- bastion.json
|
|
||||||
- masters.json
|
|
||||||
- minions.json
|
|
||||||
- clear-rg.json
|
|
|
@ -1,30 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
|
|
||||||
"contentVersion": "1.0.0.0",
|
|
||||||
"parameters": {
|
|
||||||
},
|
|
||||||
"variables": {
|
|
||||||
},
|
|
||||||
"resources": [
|
|
||||||
{
|
|
||||||
"type": "Microsoft.Compute/availabilitySets",
|
|
||||||
"name": "{{availabilitySetMasters}}",
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"properties": {
|
|
||||||
"PlatformFaultDomainCount": "{{faultDomainCount}}",
|
|
||||||
"PlatformUpdateDomainCount": "{{updateDomainCount}}"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "Microsoft.Compute/availabilitySets",
|
|
||||||
"name": "{{availabilitySetMinions}}",
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"properties": {
|
|
||||||
"PlatformFaultDomainCount": "{{faultDomainCount}}",
|
|
||||||
"PlatformUpdateDomainCount": "{{updateDomainCount}}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
|
|
||||||
"contentVersion": "1.0.0.0",
|
|
||||||
"parameters": {
|
|
||||||
},
|
|
||||||
"variables": {
|
|
||||||
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks', '{{virtualNetworkName}}')]",
|
|
||||||
"subnetAdminRef": "[concat(variables('vnetID'),'/subnets/', '{{subnetAdminName}}')]"
|
|
||||||
},
|
|
||||||
"resources": [
|
|
||||||
{% if use_bastion %}
|
|
||||||
{
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"type": "Microsoft.Network/publicIPAddresses",
|
|
||||||
"name": "{{bastionIPAddressName}}",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"properties": {
|
|
||||||
"publicIPAllocationMethod": "Static",
|
|
||||||
"dnsSettings": {
|
|
||||||
{% if bastion_domain_prefix %}
|
|
||||||
"domainNameLabel": "{{ bastion_domain_prefix }}"
|
|
||||||
{% endif %}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"type": "Microsoft.Network/networkInterfaces",
|
|
||||||
"name": "{{bastionVMName}}-nic",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"dependsOn": [
|
|
||||||
"[concat('Microsoft.Network/publicIPAddresses/', '{{bastionIPAddressName}}')]"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"ipConfigurations": [
|
|
||||||
{
|
|
||||||
"name": "BastionIpConfig",
|
|
||||||
"properties": {
|
|
||||||
"privateIPAllocationMethod": "Dynamic",
|
|
||||||
"publicIPAddress": {
|
|
||||||
"id": "[resourceId('Microsoft.Network/publicIPAddresses', '{{bastionIPAddressName}}')]"
|
|
||||||
},
|
|
||||||
"subnet": {
|
|
||||||
"id": "[variables('subnetAdminRef')]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"type": "Microsoft.Compute/virtualMachines",
|
|
||||||
"name": "{{bastionVMName}}",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"dependsOn": [
|
|
||||||
"[concat('Microsoft.Network/networkInterfaces/', '{{bastionVMName}}-nic')]"
|
|
||||||
],
|
|
||||||
"tags": {
|
|
||||||
"roles": "bastion"
|
|
||||||
},
|
|
||||||
"properties": {
|
|
||||||
"hardwareProfile": {
|
|
||||||
"vmSize": "{{bastionVmSize}}"
|
|
||||||
},
|
|
||||||
"osProfile": {
|
|
||||||
"computerName": "{{bastionVMName}}",
|
|
||||||
"adminUsername": "{{admin_username}}",
|
|
||||||
"adminPassword": "{{admin_password}}",
|
|
||||||
"linuxConfiguration": {
|
|
||||||
"disablePasswordAuthentication": "true",
|
|
||||||
"ssh": {
|
|
||||||
"publicKeys": [
|
|
||||||
{% for key in ssh_public_keys %}
|
|
||||||
{
|
|
||||||
"path": "{{sshKeyPath}}",
|
|
||||||
"keyData": "{{key}}"
|
|
||||||
}{% if loop.index < ssh_public_keys | length %},{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"storageProfile": {
|
|
||||||
"imageReference": {{imageReferenceJson}},
|
|
||||||
"osDisk": {
|
|
||||||
"name": "osdisk",
|
|
||||||
"vhd": {
|
|
||||||
"uri": "[concat('http://', '{{storageAccountName}}', '.blob.core.windows.net/vhds/', '{{bastionVMName}}', '-osdisk.vhd')]"
|
|
||||||
},
|
|
||||||
"caching": "ReadWrite",
|
|
||||||
"createOption": "FromImage"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"networkProfile": {
|
|
||||||
"networkInterfaces": [
|
|
||||||
{
|
|
||||||
"id": "[resourceId('Microsoft.Network/networkInterfaces', '{{bastionVMName}}-nic')]"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{% endif %}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
|
|
||||||
"contentVersion": "1.0.0.0",
|
|
||||||
"parameters": {},
|
|
||||||
"variables": {},
|
|
||||||
"resources": [],
|
|
||||||
"outputs": {}
|
|
||||||
}
|
|
|
@ -1,198 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
|
|
||||||
"contentVersion": "1.0.0.0",
|
|
||||||
"parameters": {
|
|
||||||
},
|
|
||||||
"variables": {
|
|
||||||
"lbDomainName": "{{nameSuffix}}-api",
|
|
||||||
"lbPublicIPAddressName": "kubernetes-api-pubip",
|
|
||||||
"lbPublicIPAddressType": "Static",
|
|
||||||
"lbPublicIPAddressID": "[resourceId('Microsoft.Network/publicIPAddresses',variables('lbPublicIPAddressName'))]",
|
|
||||||
"lbName": "kubernetes-api",
|
|
||||||
"lbID": "[resourceId('Microsoft.Network/loadBalancers',variables('lbName'))]",
|
|
||||||
|
|
||||||
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks', '{{virtualNetworkName}}')]",
|
|
||||||
"kubeMastersSubnetRef": "[concat(variables('vnetID'),'/subnets/', '{{subnetMastersName}}')]"
|
|
||||||
},
|
|
||||||
"resources": [
|
|
||||||
{
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"type": "Microsoft.Network/publicIPAddresses",
|
|
||||||
"name": "[variables('lbPublicIPAddressName')]",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"properties": {
|
|
||||||
"publicIPAllocationMethod": "[variables('lbPublicIPAddressType')]",
|
|
||||||
"dnsSettings": {
|
|
||||||
"domainNameLabel": "[variables('lbDomainName')]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"name": "[variables('lbName')]",
|
|
||||||
"type": "Microsoft.Network/loadBalancers",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"dependsOn": [
|
|
||||||
"[concat('Microsoft.Network/publicIPAddresses/', variables('lbPublicIPAddressName'))]"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"frontendIPConfigurations": [
|
|
||||||
{
|
|
||||||
"name": "kube-api-frontend",
|
|
||||||
"properties": {
|
|
||||||
"publicIPAddress": {
|
|
||||||
"id": "[variables('lbPublicIPAddressID')]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"backendAddressPools": [
|
|
||||||
{
|
|
||||||
"name": "kube-api-backend"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"loadBalancingRules": [
|
|
||||||
{
|
|
||||||
"name": "kube-api",
|
|
||||||
"properties": {
|
|
||||||
"frontendIPConfiguration": {
|
|
||||||
"id": "[concat(variables('lbID'), '/frontendIPConfigurations/kube-api-frontend')]"
|
|
||||||
},
|
|
||||||
"backendAddressPool": {
|
|
||||||
"id": "[concat(variables('lbID'), '/backendAddressPools/kube-api-backend')]"
|
|
||||||
},
|
|
||||||
"protocol": "tcp",
|
|
||||||
"frontendPort": "{{kube_apiserver_port}}",
|
|
||||||
"backendPort": "{{kube_apiserver_port}}",
|
|
||||||
"enableFloatingIP": false,
|
|
||||||
"idleTimeoutInMinutes": 5,
|
|
||||||
"probe": {
|
|
||||||
"id": "[concat(variables('lbID'), '/probes/kube-api')]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"probes": [
|
|
||||||
{
|
|
||||||
"name": "kube-api",
|
|
||||||
"properties": {
|
|
||||||
"protocol": "tcp",
|
|
||||||
"port": "{{kube_apiserver_port}}",
|
|
||||||
"intervalInSeconds": 5,
|
|
||||||
"numberOfProbes": 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{% for i in range(number_of_k8s_masters) %}
|
|
||||||
{% if not use_bastion %}
|
|
||||||
{
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"type": "Microsoft.Network/publicIPAddresses",
|
|
||||||
"name": "master-{{i}}-pubip",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"properties": {
|
|
||||||
"publicIPAllocationMethod": "Static"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{% endif %}
|
|
||||||
{
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"type": "Microsoft.Network/networkInterfaces",
|
|
||||||
"name": "master-{{i}}-nic",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"dependsOn": [
|
|
||||||
{% if not use_bastion %}
|
|
||||||
"[concat('Microsoft.Network/publicIPAddresses/', 'master-{{i}}-pubip')]",
|
|
||||||
{% endif %}
|
|
||||||
"[concat('Microsoft.Network/loadBalancers/', variables('lbName'))]"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"ipConfigurations": [
|
|
||||||
{
|
|
||||||
"name": "MastersIpConfig",
|
|
||||||
"properties": {
|
|
||||||
"privateIPAllocationMethod": "Dynamic",
|
|
||||||
{% if not use_bastion %}
|
|
||||||
"publicIPAddress": {
|
|
||||||
"id": "[resourceId('Microsoft.Network/publicIPAddresses', 'master-{{i}}-pubip')]"
|
|
||||||
},
|
|
||||||
{% endif %}
|
|
||||||
"subnet": {
|
|
||||||
"id": "[variables('kubeMastersSubnetRef')]"
|
|
||||||
},
|
|
||||||
"loadBalancerBackendAddressPools": [
|
|
||||||
{
|
|
||||||
"id": "[concat(variables('lbID'), '/backendAddressPools/kube-api-backend')]"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"networkSecurityGroup": {
|
|
||||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', '{{securityGroupName}}')]"
|
|
||||||
},
|
|
||||||
"enableIPForwarding": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "Microsoft.Compute/virtualMachines",
|
|
||||||
"name": "master-{{i}}",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"dependsOn": [
|
|
||||||
"[concat('Microsoft.Network/networkInterfaces/', 'master-{{i}}-nic')]"
|
|
||||||
],
|
|
||||||
"tags": {
|
|
||||||
"roles": "kube_control_plane,etcd"
|
|
||||||
},
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"properties": {
|
|
||||||
"availabilitySet": {
|
|
||||||
"id": "[resourceId('Microsoft.Compute/availabilitySets', '{{availabilitySetMasters}}')]"
|
|
||||||
},
|
|
||||||
"hardwareProfile": {
|
|
||||||
"vmSize": "{{masters_vm_size}}"
|
|
||||||
},
|
|
||||||
"osProfile": {
|
|
||||||
"computerName": "master-{{i}}",
|
|
||||||
"adminUsername": "{{admin_username}}",
|
|
||||||
"adminPassword": "{{admin_password}}",
|
|
||||||
"linuxConfiguration": {
|
|
||||||
"disablePasswordAuthentication": "{{disablePasswordAuthentication}}",
|
|
||||||
"ssh": {
|
|
||||||
"publicKeys": [
|
|
||||||
{% for key in ssh_public_keys %}
|
|
||||||
{
|
|
||||||
"path": "{{sshKeyPath}}",
|
|
||||||
"keyData": "{{key}}"
|
|
||||||
}{% if loop.index < ssh_public_keys | length %},{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"storageProfile": {
|
|
||||||
"imageReference": {{imageReferenceJson}},
|
|
||||||
"osDisk": {
|
|
||||||
"name": "ma{{nameSuffix}}{{i}}",
|
|
||||||
"vhd": {
|
|
||||||
"uri": "[concat('http://','{{storageAccountName}}','.blob.core.windows.net/vhds/master-{{i}}.vhd')]"
|
|
||||||
},
|
|
||||||
"caching": "ReadWrite",
|
|
||||||
"createOption": "FromImage",
|
|
||||||
"diskSizeGB": "{{masters_os_disk_size}}"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"networkProfile": {
|
|
||||||
"networkInterfaces": [
|
|
||||||
{
|
|
||||||
"id": "[resourceId('Microsoft.Network/networkInterfaces', 'master-{{i}}-nic')]"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} {% if not loop.last %},{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,115 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
|
|
||||||
"contentVersion": "1.0.0.0",
|
|
||||||
"parameters": {
|
|
||||||
},
|
|
||||||
"variables": {
|
|
||||||
"vnetID": "[resourceId('Microsoft.Network/virtualNetworks', '{{virtualNetworkName}}')]",
|
|
||||||
"kubeMinionsSubnetRef": "[concat(variables('vnetID'),'/subnets/', '{{subnetMinionsName}}')]"
|
|
||||||
},
|
|
||||||
"resources": [
|
|
||||||
{% for i in range(number_of_k8s_nodes) %}
|
|
||||||
{% if not use_bastion %}
|
|
||||||
{
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"type": "Microsoft.Network/publicIPAddresses",
|
|
||||||
"name": "minion-{{i}}-pubip",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"properties": {
|
|
||||||
"publicIPAllocationMethod": "Static"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{% endif %}
|
|
||||||
{
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"type": "Microsoft.Network/networkInterfaces",
|
|
||||||
"name": "minion-{{i}}-nic",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"dependsOn": [
|
|
||||||
{% if not use_bastion %}
|
|
||||||
"[concat('Microsoft.Network/publicIPAddresses/', 'minion-{{i}}-pubip')]"
|
|
||||||
{% endif %}
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"ipConfigurations": [
|
|
||||||
{
|
|
||||||
"name": "MinionsIpConfig",
|
|
||||||
"properties": {
|
|
||||||
"privateIPAllocationMethod": "Dynamic",
|
|
||||||
{% if not use_bastion %}
|
|
||||||
"publicIPAddress": {
|
|
||||||
"id": "[resourceId('Microsoft.Network/publicIPAddresses', 'minion-{{i}}-pubip')]"
|
|
||||||
},
|
|
||||||
{% endif %}
|
|
||||||
"subnet": {
|
|
||||||
"id": "[variables('kubeMinionsSubnetRef')]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"networkSecurityGroup": {
|
|
||||||
"id": "[resourceId('Microsoft.Network/networkSecurityGroups', '{{securityGroupName}}')]"
|
|
||||||
},
|
|
||||||
"enableIPForwarding": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "Microsoft.Compute/virtualMachines",
|
|
||||||
"name": "minion-{{i}}",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"dependsOn": [
|
|
||||||
"[concat('Microsoft.Network/networkInterfaces/', 'minion-{{i}}-nic')]"
|
|
||||||
],
|
|
||||||
"tags": {
|
|
||||||
"roles": "kube_node"
|
|
||||||
},
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"properties": {
|
|
||||||
"availabilitySet": {
|
|
||||||
"id": "[resourceId('Microsoft.Compute/availabilitySets', '{{availabilitySetMinions}}')]"
|
|
||||||
},
|
|
||||||
"hardwareProfile": {
|
|
||||||
"vmSize": "{{minions_vm_size}}"
|
|
||||||
},
|
|
||||||
"osProfile": {
|
|
||||||
"computerName": "minion-{{i}}",
|
|
||||||
"adminUsername": "{{admin_username}}",
|
|
||||||
"adminPassword": "{{admin_password}}",
|
|
||||||
"linuxConfiguration": {
|
|
||||||
"disablePasswordAuthentication": "{{disablePasswordAuthentication}}",
|
|
||||||
"ssh": {
|
|
||||||
"publicKeys": [
|
|
||||||
{% for key in ssh_public_keys %}
|
|
||||||
{
|
|
||||||
"path": "{{sshKeyPath}}",
|
|
||||||
"keyData": "{{key}}"
|
|
||||||
}{% if loop.index < ssh_public_keys | length %},{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"storageProfile": {
|
|
||||||
"imageReference": {{imageReferenceJson}},
|
|
||||||
"osDisk": {
|
|
||||||
"name": "mi{{nameSuffix}}{{i}}",
|
|
||||||
"vhd": {
|
|
||||||
"uri": "[concat('http://','{{storageAccountName}}','.blob.core.windows.net/vhds/minion-{{i}}.vhd')]"
|
|
||||||
},
|
|
||||||
"caching": "ReadWrite",
|
|
||||||
"createOption": "FromImage",
|
|
||||||
"diskSizeGB": "{{minions_os_disk_size}}"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"networkProfile": {
|
|
||||||
"networkInterfaces": [
|
|
||||||
{
|
|
||||||
"id": "[resourceId('Microsoft.Network/networkInterfaces', 'minion-{{i}}-nic')]"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} {% if not loop.last %},{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,109 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
|
|
||||||
"contentVersion": "1.0.0.0",
|
|
||||||
"parameters": {
|
|
||||||
},
|
|
||||||
"variables": {
|
|
||||||
},
|
|
||||||
"resources": [
|
|
||||||
{
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"type": "Microsoft.Network/routeTables",
|
|
||||||
"name": "{{routeTableName}}",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"properties": {
|
|
||||||
"routes": [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "Microsoft.Network/virtualNetworks",
|
|
||||||
"name": "{{virtualNetworkName}}",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"dependsOn": [
|
|
||||||
"[concat('Microsoft.Network/routeTables/', '{{routeTableName}}')]"
|
|
||||||
],
|
|
||||||
"properties": {
|
|
||||||
"addressSpace": {
|
|
||||||
"addressPrefixes": [
|
|
||||||
"{{azure_vnet_cidr}}"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"subnets": [
|
|
||||||
{
|
|
||||||
"name": "{{subnetMastersName}}",
|
|
||||||
"properties": {
|
|
||||||
"addressPrefix": "{{azure_masters_cidr}}",
|
|
||||||
"routeTable": {
|
|
||||||
"id": "[resourceId('Microsoft.Network/routeTables', '{{routeTableName}}')]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "{{subnetMinionsName}}",
|
|
||||||
"properties": {
|
|
||||||
"addressPrefix": "{{azure_minions_cidr}}",
|
|
||||||
"routeTable": {
|
|
||||||
"id": "[resourceId('Microsoft.Network/routeTables', '{{routeTableName}}')]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{% if use_bastion %}
|
|
||||||
,{
|
|
||||||
"name": "{{subnetAdminName}}",
|
|
||||||
"properties": {
|
|
||||||
"addressPrefix": "{{azure_admin_cidr}}",
|
|
||||||
"routeTable": {
|
|
||||||
"id": "[resourceId('Microsoft.Network/routeTables', '{{routeTableName}}')]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{% endif %}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"type": "Microsoft.Network/networkSecurityGroups",
|
|
||||||
"name": "{{securityGroupName}}",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"properties": {
|
|
||||||
"securityRules": [
|
|
||||||
{% if not use_bastion %}
|
|
||||||
{
|
|
||||||
"name": "ssh",
|
|
||||||
"properties": {
|
|
||||||
"description": "Allow SSH",
|
|
||||||
"protocol": "Tcp",
|
|
||||||
"sourcePortRange": "*",
|
|
||||||
"destinationPortRange": "22",
|
|
||||||
"sourceAddressPrefix": "Internet",
|
|
||||||
"destinationAddressPrefix": "*",
|
|
||||||
"access": "Allow",
|
|
||||||
"priority": 100,
|
|
||||||
"direction": "Inbound"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{% endif %}
|
|
||||||
{
|
|
||||||
"name": "kube-api",
|
|
||||||
"properties": {
|
|
||||||
"description": "Allow secure kube-api",
|
|
||||||
"protocol": "Tcp",
|
|
||||||
"sourcePortRange": "*",
|
|
||||||
"destinationPortRange": "{{kube_apiserver_port}}",
|
|
||||||
"sourceAddressPrefix": "Internet",
|
|
||||||
"destinationAddressPrefix": "*",
|
|
||||||
"access": "Allow",
|
|
||||||
"priority": 101,
|
|
||||||
"direction": "Inbound"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"resources": [],
|
|
||||||
"dependsOn": []
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
|
|
||||||
"contentVersion": "1.0.0.0",
|
|
||||||
"parameters": {
|
|
||||||
},
|
|
||||||
"variables": {
|
|
||||||
},
|
|
||||||
"resources": [
|
|
||||||
{
|
|
||||||
"type": "Microsoft.Storage/storageAccounts",
|
|
||||||
"name": "{{storageAccountName}}",
|
|
||||||
"location": "[resourceGroup().location]",
|
|
||||||
"apiVersion": "{{apiVersion}}",
|
|
||||||
"properties": {
|
|
||||||
"accountType": "{{storageAccountType}}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
|
@ -1,177 +0,0 @@
|
||||||
# Kubespray DIND experimental setup
|
|
||||||
|
|
||||||
This ansible playbook creates local docker containers
|
|
||||||
to serve as Kubernetes "nodes", which in turn will run
|
|
||||||
"normal" Kubernetes docker containers, a mode usually
|
|
||||||
called DIND (Docker-IN-Docker).
|
|
||||||
|
|
||||||
The playbook has two roles:
|
|
||||||
|
|
||||||
- dind-host: creates the "nodes" as containers in localhost, with
|
|
||||||
appropriate settings for DIND (privileged, volume mapping for dind
|
|
||||||
storage, etc).
|
|
||||||
- dind-cluster: customizes each node container to have required
|
|
||||||
system packages installed, and some utils (swapoff, lsattr)
|
|
||||||
symlinked to /bin/true to ease mimicking a real node.
|
|
||||||
|
|
||||||
This playbook has been test with Ubuntu 16.04 as host and ubuntu:16.04
|
|
||||||
as docker images (note that dind-cluster has specific customization
|
|
||||||
for these images).
|
|
||||||
|
|
||||||
The playbook also creates a `/tmp/kubespray.dind.inventory_builder.sh`
|
|
||||||
helper (wraps up running `contrib/inventory_builder/inventory.py` with
|
|
||||||
node containers IPs and prefix).
|
|
||||||
|
|
||||||
## Deploying
|
|
||||||
|
|
||||||
See below for a complete successful run:
|
|
||||||
|
|
||||||
1. Create the node containers
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# From the kubespray root dir
|
|
||||||
cd contrib/dind
|
|
||||||
pip install -r requirements.txt
|
|
||||||
|
|
||||||
ansible-playbook -i hosts dind-cluster.yaml
|
|
||||||
|
|
||||||
# Back to kubespray root
|
|
||||||
cd ../..
|
|
||||||
```
|
|
||||||
|
|
||||||
NOTE: if the playbook run fails with something like below error
|
|
||||||
message, you may need to specifically set `ansible_python_interpreter`,
|
|
||||||
see `./hosts` file for an example expanded localhost entry.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
failed: [localhost] (item=kube-node1) => {"changed": false, "item": "kube-node1", "msg": "Failed to import docker or docker-py - No module named requests.exceptions. Try `pip install docker` or `pip install docker-py` (Python 2.6)"}
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Customize kubespray-dind.yaml
|
|
||||||
|
|
||||||
Note that there's coupling between above created node containers
|
|
||||||
and `kubespray-dind.yaml` settings, in particular regarding selected `node_distro`
|
|
||||||
(as set in `group_vars/all/all.yaml`), and docker settings.
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$EDITOR contrib/dind/kubespray-dind.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Prepare the inventory and run the playbook
|
|
||||||
|
|
||||||
```shell
|
|
||||||
INVENTORY_DIR=inventory/local-dind
|
|
||||||
mkdir -p ${INVENTORY_DIR}
|
|
||||||
rm -f ${INVENTORY_DIR}/hosts.ini
|
|
||||||
CONFIG_FILE=${INVENTORY_DIR}/hosts.ini /tmp/kubespray.dind.inventory_builder.sh
|
|
||||||
|
|
||||||
ansible-playbook --become -e ansible_ssh_user=debian -i ${INVENTORY_DIR}/hosts.ini cluster.yml --extra-vars @contrib/dind/kubespray-dind.yaml
|
|
||||||
```
|
|
||||||
|
|
||||||
NOTE: You could also test other distros without editing files by
|
|
||||||
passing `--extra-vars` as per below commandline,
|
|
||||||
replacing `DISTRO` by either `debian`, `ubuntu`, `centos`, `fedora`:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
cd contrib/dind
|
|
||||||
ansible-playbook -i hosts dind-cluster.yaml --extra-vars node_distro=DISTRO
|
|
||||||
|
|
||||||
cd ../..
|
|
||||||
CONFIG_FILE=inventory/local-dind/hosts.ini /tmp/kubespray.dind.inventory_builder.sh
|
|
||||||
ansible-playbook --become -e ansible_ssh_user=DISTRO -i inventory/local-dind/hosts.ini cluster.yml --extra-vars @contrib/dind/kubespray-dind.yaml --extra-vars bootstrap_os=DISTRO
|
|
||||||
```
|
|
||||||
|
|
||||||
## Resulting deployment
|
|
||||||
|
|
||||||
See below to get an idea on how a completed deployment looks like,
|
|
||||||
from the host where you ran kubespray playbooks.
|
|
||||||
|
|
||||||
### node_distro: debian
|
|
||||||
|
|
||||||
Running from an Ubuntu Xenial host:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ uname -a
|
|
||||||
Linux ip-xx-xx-xx-xx 4.4.0-1069-aws #79-Ubuntu SMP Mon Sep 24
|
|
||||||
15:01:41 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
|
|
||||||
|
|
||||||
$ docker ps
|
|
||||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
|
||||||
1835dd183b75 debian:9.5 "sh -c 'apt-get -qy …" 43 minutes ago Up 43 minutes kube-node5
|
|
||||||
30b0af8d2924 debian:9.5 "sh -c 'apt-get -qy …" 43 minutes ago Up 43 minutes kube-node4
|
|
||||||
3e0d1510c62f debian:9.5 "sh -c 'apt-get -qy …" 43 minutes ago Up 43 minutes kube-node3
|
|
||||||
738993566f94 debian:9.5 "sh -c 'apt-get -qy …" 44 minutes ago Up 44 minutes kube-node2
|
|
||||||
c581ef662ed2 debian:9.5 "sh -c 'apt-get -qy …" 44 minutes ago Up 44 minutes kube-node1
|
|
||||||
|
|
||||||
$ docker exec kube-node1 kubectl get node
|
|
||||||
NAME STATUS ROLES AGE VERSION
|
|
||||||
kube-node1 Ready master,node 18m v1.12.1
|
|
||||||
kube-node2 Ready master,node 17m v1.12.1
|
|
||||||
kube-node3 Ready node 17m v1.12.1
|
|
||||||
kube-node4 Ready node 17m v1.12.1
|
|
||||||
kube-node5 Ready node 17m v1.12.1
|
|
||||||
|
|
||||||
$ docker exec kube-node1 kubectl get pod --all-namespaces
|
|
||||||
NAMESPACE NAME READY STATUS RESTARTS AGE
|
|
||||||
default netchecker-agent-67489 1/1 Running 0 2m51s
|
|
||||||
default netchecker-agent-6qq6s 1/1 Running 0 2m51s
|
|
||||||
default netchecker-agent-fsw92 1/1 Running 0 2m51s
|
|
||||||
default netchecker-agent-fw6tl 1/1 Running 0 2m51s
|
|
||||||
default netchecker-agent-hostnet-8f2zb 1/1 Running 0 3m
|
|
||||||
default netchecker-agent-hostnet-gq7ml 1/1 Running 0 3m
|
|
||||||
default netchecker-agent-hostnet-jfkgv 1/1 Running 0 3m
|
|
||||||
default netchecker-agent-hostnet-kwfwx 1/1 Running 0 3m
|
|
||||||
default netchecker-agent-hostnet-r46nm 1/1 Running 0 3m
|
|
||||||
default netchecker-agent-lxdrn 1/1 Running 0 2m51s
|
|
||||||
default netchecker-server-864bd4c897-9vstl 1/1 Running 0 2m40s
|
|
||||||
default sh-68fcc6db45-qf55h 1/1 Running 1 12m
|
|
||||||
kube-system coredns-7598f59475-6vknq 1/1 Running 0 14m
|
|
||||||
kube-system coredns-7598f59475-l5q5x 1/1 Running 0 14m
|
|
||||||
kube-system kube-apiserver-kube-node1 1/1 Running 0 17m
|
|
||||||
kube-system kube-apiserver-kube-node2 1/1 Running 0 18m
|
|
||||||
kube-system kube-controller-manager-kube-node1 1/1 Running 0 18m
|
|
||||||
kube-system kube-controller-manager-kube-node2 1/1 Running 0 18m
|
|
||||||
kube-system kube-proxy-5xx9d 1/1 Running 0 17m
|
|
||||||
kube-system kube-proxy-cdqq4 1/1 Running 0 17m
|
|
||||||
kube-system kube-proxy-n64ls 1/1 Running 0 17m
|
|
||||||
kube-system kube-proxy-pswmj 1/1 Running 0 18m
|
|
||||||
kube-system kube-proxy-x89qw 1/1 Running 0 18m
|
|
||||||
kube-system kube-scheduler-kube-node1 1/1 Running 4 17m
|
|
||||||
kube-system kube-scheduler-kube-node2 1/1 Running 4 18m
|
|
||||||
kube-system kubernetes-dashboard-5db4d9f45f-548rl 1/1 Running 0 14m
|
|
||||||
kube-system nginx-proxy-kube-node3 1/1 Running 4 17m
|
|
||||||
kube-system nginx-proxy-kube-node4 1/1 Running 4 17m
|
|
||||||
kube-system nginx-proxy-kube-node5 1/1 Running 4 17m
|
|
||||||
kube-system weave-net-42bfr 2/2 Running 0 16m
|
|
||||||
kube-system weave-net-6gt8m 2/2 Running 0 16m
|
|
||||||
kube-system weave-net-88nnc 2/2 Running 0 16m
|
|
||||||
kube-system weave-net-shckr 2/2 Running 0 16m
|
|
||||||
kube-system weave-net-xr46t 2/2 Running 0 16m
|
|
||||||
|
|
||||||
$ docker exec kube-node1 curl -s http://localhost:31081/api/v1/connectivity_check
|
|
||||||
{"Message":"All 10 pods successfully reported back to the server","Absent":null,"Outdated":null}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Using ./run-test-distros.sh
|
|
||||||
|
|
||||||
You can use `./run-test-distros.sh` to run a set of tests via DIND,
|
|
||||||
and excerpt from this script, to get an idea:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# The SPEC file(s) must have two arrays as e.g.
|
|
||||||
# DISTROS=(debian centos)
|
|
||||||
# EXTRAS=(
|
|
||||||
# 'kube_network_plugin=calico'
|
|
||||||
# 'kube_network_plugin=flannel'
|
|
||||||
# 'kube_network_plugin=weave'
|
|
||||||
# )
|
|
||||||
# that will be tested in a "combinatory" way (e.g. from above there'll be
|
|
||||||
# be 6 test runs), creating a sequenced <spec_filename>-nn.out with each output.
|
|
||||||
#
|
|
||||||
# Each $EXTRAS element will be whitespace split, and passed as --extra-vars
|
|
||||||
# to main kubespray ansible-playbook run.
|
|
||||||
```
|
|
||||||
|
|
||||||
See e.g. `test-some_distros-most_CNIs.env` and
|
|
||||||
`test-some_distros-kube_router_combo.env` in particular for a richer
|
|
||||||
set of CNI specific `--extra-vars` combo.
|
|
|
@ -1,9 +0,0 @@
|
||||||
---
|
|
||||||
- hosts: localhost
|
|
||||||
gather_facts: False
|
|
||||||
roles:
|
|
||||||
- { role: dind-host }
|
|
||||||
|
|
||||||
- hosts: containers
|
|
||||||
roles:
|
|
||||||
- { role: dind-cluster }
|
|
|
@ -1,3 +0,0 @@
|
||||||
---
|
|
||||||
# See distro.yaml for supported node_distro images
|
|
||||||
node_distro: debian
|
|
|
@ -1,41 +0,0 @@
|
||||||
---
|
|
||||||
distro_settings:
|
|
||||||
debian: &DEBIAN
|
|
||||||
image: "debian:9.5"
|
|
||||||
user: "debian"
|
|
||||||
pid1_exe: /lib/systemd/systemd
|
|
||||||
init: |
|
|
||||||
sh -c "apt-get -qy update && apt-get -qy install systemd-sysv dbus && exec /sbin/init"
|
|
||||||
raw_setup: apt-get -qy update && apt-get -qy install dbus python sudo iproute2
|
|
||||||
raw_setup_done: test -x /usr/bin/sudo
|
|
||||||
agetty_svc: getty@*
|
|
||||||
ssh_service: ssh
|
|
||||||
extra_packages: []
|
|
||||||
ubuntu:
|
|
||||||
<<: *DEBIAN
|
|
||||||
image: "ubuntu:16.04"
|
|
||||||
user: "ubuntu"
|
|
||||||
init: |
|
|
||||||
/sbin/init
|
|
||||||
centos: &CENTOS
|
|
||||||
image: "centos:7"
|
|
||||||
user: "centos"
|
|
||||||
pid1_exe: /usr/lib/systemd/systemd
|
|
||||||
init: |
|
|
||||||
/sbin/init
|
|
||||||
raw_setup: yum -qy install policycoreutils dbus python sudo iproute iptables
|
|
||||||
raw_setup_done: test -x /usr/bin/sudo
|
|
||||||
agetty_svc: getty@* serial-getty@*
|
|
||||||
ssh_service: sshd
|
|
||||||
extra_packages: []
|
|
||||||
fedora:
|
|
||||||
<<: *CENTOS
|
|
||||||
image: "fedora:latest"
|
|
||||||
user: "fedora"
|
|
||||||
raw_setup: yum -qy install policycoreutils dbus python sudo iproute iptables; mkdir -p /etc/modules-load.d
|
|
||||||
extra_packages:
|
|
||||||
- hostname
|
|
||||||
- procps
|
|
||||||
- findutils
|
|
||||||
- kmod
|
|
||||||
- iputils
|
|
|
@ -1,15 +0,0 @@
|
||||||
[local]
|
|
||||||
# If you created a virtualenv for ansible, you may need to specify running the
|
|
||||||
# python binary from there instead:
|
|
||||||
#localhost ansible_connection=local ansible_python_interpreter=/home/user/kubespray/.venv/bin/python
|
|
||||||
localhost ansible_connection=local
|
|
||||||
|
|
||||||
[containers]
|
|
||||||
kube-node1
|
|
||||||
kube-node2
|
|
||||||
kube-node3
|
|
||||||
kube-node4
|
|
||||||
kube-node5
|
|
||||||
|
|
||||||
[containers:vars]
|
|
||||||
ansible_connection=docker
|
|
|
@ -1,22 +0,0 @@
|
||||||
---
|
|
||||||
# kubespray-dind.yaml: minimal kubespray ansible playbook usable for DIND
|
|
||||||
# See contrib/dind/README.md
|
|
||||||
kube_api_anonymous_auth: true
|
|
||||||
|
|
||||||
kubelet_fail_swap_on: false
|
|
||||||
|
|
||||||
# Docker nodes need to have been created with same "node_distro: debian"
|
|
||||||
# at contrib/dind/group_vars/all/all.yaml
|
|
||||||
bootstrap_os: debian
|
|
||||||
|
|
||||||
docker_version: latest
|
|
||||||
|
|
||||||
docker_storage_options: -s overlay2 --storage-opt overlay2.override_kernel_check=true -g /dind/docker
|
|
||||||
|
|
||||||
dns_mode: coredns
|
|
||||||
|
|
||||||
deploy_netchecker: True
|
|
||||||
netcheck_agent_image_repo: quay.io/l23network/k8s-netchecker-agent
|
|
||||||
netcheck_server_image_repo: quay.io/l23network/k8s-netchecker-server
|
|
||||||
netcheck_agent_image_tag: v1.0
|
|
||||||
netcheck_server_image_tag: v1.0
|
|
|
@ -1 +0,0 @@
|
||||||
docker
|
|
|
@ -1,73 +0,0 @@
|
||||||
---
|
|
||||||
- name: set_fact distro_setup
|
|
||||||
set_fact:
|
|
||||||
distro_setup: "{{ distro_settings[node_distro] }}"
|
|
||||||
|
|
||||||
- name: set_fact other distro settings
|
|
||||||
set_fact:
|
|
||||||
distro_user: "{{ distro_setup['user'] }}"
|
|
||||||
distro_ssh_service: "{{ distro_setup['ssh_service'] }}"
|
|
||||||
distro_extra_packages: "{{ distro_setup['extra_packages'] }}"
|
|
||||||
|
|
||||||
- name: Null-ify some linux tools to ease DIND
|
|
||||||
file:
|
|
||||||
src: "/bin/true"
|
|
||||||
dest: "{{ item }}"
|
|
||||||
state: link
|
|
||||||
force: yes
|
|
||||||
with_items:
|
|
||||||
# DIND box may have swap enable, don't bother
|
|
||||||
- /sbin/swapoff
|
|
||||||
# /etc/hosts handling would fail on trying to copy file attributes on edit,
|
|
||||||
# void it by successfully returning nil output
|
|
||||||
- /usr/bin/lsattr
|
|
||||||
# disable selinux-isms, sp needed if running on non-Selinux host
|
|
||||||
- /usr/sbin/semodule
|
|
||||||
|
|
||||||
- name: Void installing dpkg docs and man pages on Debian based distros
|
|
||||||
copy:
|
|
||||||
content: |
|
|
||||||
# Delete locales
|
|
||||||
path-exclude=/usr/share/locale/*
|
|
||||||
# Delete man pages
|
|
||||||
path-exclude=/usr/share/man/*
|
|
||||||
# Delete docs
|
|
||||||
path-exclude=/usr/share/doc/*
|
|
||||||
path-include=/usr/share/doc/*/copyright
|
|
||||||
dest: /etc/dpkg/dpkg.cfg.d/01_nodoc
|
|
||||||
mode: 0644
|
|
||||||
when:
|
|
||||||
- ansible_os_family == 'Debian'
|
|
||||||
|
|
||||||
- name: Install system packages to better match a full-fledge node
|
|
||||||
package:
|
|
||||||
name: "{{ item }}"
|
|
||||||
state: present
|
|
||||||
with_items: "{{ distro_extra_packages }} + [ 'rsyslog', 'openssh-server' ]"
|
|
||||||
|
|
||||||
- name: Start needed services
|
|
||||||
service:
|
|
||||||
name: "{{ item }}"
|
|
||||||
state: started
|
|
||||||
with_items:
|
|
||||||
- rsyslog
|
|
||||||
- "{{ distro_ssh_service }}"
|
|
||||||
|
|
||||||
- name: Create distro user "{{ distro_user }}"
|
|
||||||
user:
|
|
||||||
name: "{{ distro_user }}"
|
|
||||||
uid: 1000
|
|
||||||
# groups: sudo
|
|
||||||
append: yes
|
|
||||||
|
|
||||||
- name: Allow password-less sudo to "{{ distro_user }}"
|
|
||||||
copy:
|
|
||||||
content: "{{ distro_user }} ALL=(ALL) NOPASSWD:ALL"
|
|
||||||
dest: "/etc/sudoers.d/{{ distro_user }}"
|
|
||||||
mode: 0640
|
|
||||||
|
|
||||||
- name: Add my pubkey to "{{ distro_user }}" user authorized keys
|
|
||||||
authorized_key:
|
|
||||||
user: "{{ distro_user }}"
|
|
||||||
state: present
|
|
||||||
key: "{{ lookup('file', lookup('env','HOME') + '/.ssh/id_rsa.pub') }}"
|
|
|
@ -1,88 +0,0 @@
|
||||||
---
|
|
||||||
- name: set_fact distro_setup
|
|
||||||
set_fact:
|
|
||||||
distro_setup: "{{ distro_settings[node_distro] }}"
|
|
||||||
|
|
||||||
- name: set_fact other distro settings
|
|
||||||
set_fact:
|
|
||||||
distro_image: "{{ distro_setup['image'] }}"
|
|
||||||
distro_init: "{{ distro_setup['init'] }}"
|
|
||||||
distro_pid1_exe: "{{ distro_setup['pid1_exe'] }}"
|
|
||||||
distro_raw_setup: "{{ distro_setup['raw_setup'] }}"
|
|
||||||
distro_raw_setup_done: "{{ distro_setup['raw_setup_done'] }}"
|
|
||||||
distro_agetty_svc: "{{ distro_setup['agetty_svc'] }}"
|
|
||||||
|
|
||||||
- name: Create dind node containers from "containers" inventory section
|
|
||||||
docker_container:
|
|
||||||
image: "{{ distro_image }}"
|
|
||||||
name: "{{ item }}"
|
|
||||||
state: started
|
|
||||||
hostname: "{{ item }}"
|
|
||||||
command: "{{ distro_init }}"
|
|
||||||
# recreate: yes
|
|
||||||
privileged: true
|
|
||||||
tmpfs:
|
|
||||||
- /sys/module/nf_conntrack/parameters
|
|
||||||
volumes:
|
|
||||||
- /boot:/boot
|
|
||||||
- /lib/modules:/lib/modules
|
|
||||||
- "{{ item }}:/dind/docker"
|
|
||||||
register: containers
|
|
||||||
with_items: "{{ groups.containers }}"
|
|
||||||
tags:
|
|
||||||
- addresses
|
|
||||||
|
|
||||||
- name: Gather list of containers IPs
|
|
||||||
set_fact:
|
|
||||||
addresses: "{{ containers.results | map(attribute='ansible_facts') | map(attribute='docker_container') | map(attribute='NetworkSettings') | map(attribute='IPAddress') | list }}"
|
|
||||||
tags:
|
|
||||||
- addresses
|
|
||||||
|
|
||||||
- name: Create inventory_builder helper already set with the list of node containers' IPs
|
|
||||||
template:
|
|
||||||
src: inventory_builder.sh.j2
|
|
||||||
dest: /tmp/kubespray.dind.inventory_builder.sh
|
|
||||||
mode: 0755
|
|
||||||
tags:
|
|
||||||
- addresses
|
|
||||||
|
|
||||||
- name: Install needed packages into node containers via raw, need to wait for possible systemd packages to finish installing
|
|
||||||
raw: |
|
|
||||||
# agetty processes churn a lot of cpu time failing on inexistent ttys, early STOP them, to rip them in below task
|
|
||||||
pkill -STOP agetty || true
|
|
||||||
{{ distro_raw_setup_done }} && echo SKIPPED && exit 0
|
|
||||||
until [ "$(readlink /proc/1/exe)" = "{{ distro_pid1_exe }}" ] ; do sleep 1; done
|
|
||||||
{{ distro_raw_setup }}
|
|
||||||
delegate_to: "{{ item._ansible_item_label|default(item.item) }}"
|
|
||||||
with_items: "{{ containers.results }}"
|
|
||||||
register: result
|
|
||||||
changed_when: result.stdout.find("SKIPPED") < 0
|
|
||||||
|
|
||||||
- name: Remove gettys from node containers
|
|
||||||
raw: |
|
|
||||||
until test -S /var/run/dbus/system_bus_socket; do sleep 1; done
|
|
||||||
systemctl disable {{ distro_agetty_svc }}
|
|
||||||
systemctl stop {{ distro_agetty_svc }}
|
|
||||||
delegate_to: "{{ item._ansible_item_label|default(item.item) }}"
|
|
||||||
with_items: "{{ containers.results }}"
|
|
||||||
changed_when: false
|
|
||||||
|
|
||||||
# Running systemd-machine-id-setup doesn't create a unique id for each node container on Debian,
|
|
||||||
# handle manually
|
|
||||||
- name: Re-create unique machine-id (as we may just get what comes in the docker image), needed by some CNIs for mac address seeding (notably weave) # noqa 301
|
|
||||||
raw: |
|
|
||||||
echo {{ item | hash('sha1') }} > /etc/machine-id.new
|
|
||||||
mv -b /etc/machine-id.new /etc/machine-id
|
|
||||||
cmp /etc/machine-id /etc/machine-id~ || true
|
|
||||||
systemctl daemon-reload
|
|
||||||
delegate_to: "{{ item._ansible_item_label|default(item.item) }}"
|
|
||||||
with_items: "{{ containers.results }}"
|
|
||||||
|
|
||||||
- name: Early hack image install to adapt for DIND
|
|
||||||
# noqa 302 - this task uses the raw module intentionally
|
|
||||||
raw: |
|
|
||||||
rm -fv /usr/bin/udevadm /usr/sbin/udevadm
|
|
||||||
delegate_to: "{{ item._ansible_item_label|default(item.item) }}"
|
|
||||||
with_items: "{{ containers.results }}"
|
|
||||||
register: result
|
|
||||||
changed_when: result.stdout.find("removed") >= 0
|
|
|
@ -1,3 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# NOTE: if you change HOST_PREFIX, you also need to edit ./hosts [containers] section
|
|
||||||
HOST_PREFIX=kube-node python3 contrib/inventory_builder/inventory.py {% for ip in addresses %} {{ ip }} {% endfor %}
|
|
|
@ -1,93 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
# Q&D test'em all: creates full DIND kubespray deploys
|
|
||||||
# for each distro, verifying it via netchecker.
|
|
||||||
|
|
||||||
info() {
|
|
||||||
local msg="$*"
|
|
||||||
local date="$(date -Isec)"
|
|
||||||
echo "INFO: [$date] $msg"
|
|
||||||
}
|
|
||||||
pass_or_fail() {
|
|
||||||
local rc="$?"
|
|
||||||
local msg="$*"
|
|
||||||
local date="$(date -Isec)"
|
|
||||||
[ $rc -eq 0 ] && echo "PASS: [$date] $msg" || echo "FAIL: [$date] $msg"
|
|
||||||
return $rc
|
|
||||||
}
|
|
||||||
test_distro() {
|
|
||||||
local distro=${1:?};shift
|
|
||||||
local extra="${*:-}"
|
|
||||||
local prefix="${distro[${extra}]}"
|
|
||||||
ansible-playbook -i hosts dind-cluster.yaml -e node_distro=$distro
|
|
||||||
pass_or_fail "$prefix: dind-nodes" || return 1
|
|
||||||
(cd ../..
|
|
||||||
INVENTORY_DIR=inventory/local-dind
|
|
||||||
mkdir -p ${INVENTORY_DIR}
|
|
||||||
rm -f ${INVENTORY_DIR}/hosts.ini
|
|
||||||
CONFIG_FILE=${INVENTORY_DIR}/hosts.ini /tmp/kubespray.dind.inventory_builder.sh
|
|
||||||
# expand $extra with -e in front of each word
|
|
||||||
extra_args=""; for extra_arg in $extra; do extra_args="$extra_args -e $extra_arg"; done
|
|
||||||
ansible-playbook --become -e ansible_ssh_user=$distro -i \
|
|
||||||
${INVENTORY_DIR}/hosts.ini cluster.yml \
|
|
||||||
-e @contrib/dind/kubespray-dind.yaml -e bootstrap_os=$distro ${extra_args}
|
|
||||||
pass_or_fail "$prefix: kubespray"
|
|
||||||
) || return 1
|
|
||||||
local node0=${NODES[0]}
|
|
||||||
docker exec ${node0} kubectl get pod --all-namespaces
|
|
||||||
pass_or_fail "$prefix: kube-api" || return 1
|
|
||||||
let retries=60
|
|
||||||
while ((retries--)); do
|
|
||||||
# Some CNI may set NodePort on "main" node interface address (thus no localhost NodePort)
|
|
||||||
# e.g. kube-router: https://github.com/cloudnativelabs/kube-router/pull/217
|
|
||||||
docker exec ${node0} curl -m2 -s http://${NETCHECKER_HOST:?}:31081/api/v1/connectivity_check | grep successfully && break
|
|
||||||
sleep 2
|
|
||||||
done
|
|
||||||
[ $retries -ge 0 ]
|
|
||||||
pass_or_fail "$prefix: netcheck" || return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
NODES=($(egrep ^kube_node hosts))
|
|
||||||
NETCHECKER_HOST=localhost
|
|
||||||
|
|
||||||
: ${OUTPUT_DIR:=./out}
|
|
||||||
mkdir -p ${OUTPUT_DIR}
|
|
||||||
|
|
||||||
# The SPEC file(s) must have two arrays as e.g.
|
|
||||||
# DISTROS=(debian centos)
|
|
||||||
# EXTRAS=(
|
|
||||||
# 'kube_network_plugin=calico'
|
|
||||||
# 'kube_network_plugin=flannel'
|
|
||||||
# 'kube_network_plugin=weave'
|
|
||||||
# )
|
|
||||||
# that will be tested in a "combinatory" way (e.g. from above there'll be
|
|
||||||
# be 6 test runs), creating a sequenced <spec_filename>-nn.out with each output.
|
|
||||||
#
|
|
||||||
# Each $EXTRAS element will be whitespace split, and passed as --extra-vars
|
|
||||||
# to main kubespray ansible-playbook run.
|
|
||||||
|
|
||||||
SPECS=${*:?Missing SPEC files, e.g. test-most_distros-some_CNIs.env}
|
|
||||||
for spec in ${SPECS}; do
|
|
||||||
unset DISTROS EXTRAS
|
|
||||||
echo "Loading file=${spec} ..."
|
|
||||||
. ${spec} || continue
|
|
||||||
: ${DISTROS:?} || continue
|
|
||||||
echo "DISTROS:" "${DISTROS[@]}"
|
|
||||||
echo "EXTRAS->"
|
|
||||||
printf " %s\n" "${EXTRAS[@]}"
|
|
||||||
let n=1
|
|
||||||
for distro in "${DISTROS[@]}"; do
|
|
||||||
for extra in "${EXTRAS[@]:-NULL}"; do
|
|
||||||
# Magic value to let this for run once:
|
|
||||||
[[ ${extra} == NULL ]] && unset extra
|
|
||||||
docker rm -f "${NODES[@]}"
|
|
||||||
printf -v file_out "%s/%s-%02d.out" ${OUTPUT_DIR} ${spec} $((n++))
|
|
||||||
{
|
|
||||||
info "${distro}[${extra}] START: file_out=${file_out}"
|
|
||||||
time test_distro ${distro} ${extra}
|
|
||||||
} |& tee ${file_out}
|
|
||||||
# sleeping for the sake of the human to verify if they want
|
|
||||||
sleep 2m
|
|
||||||
done
|
|
||||||
done
|
|
||||||
done
|
|
||||||
egrep -H '^(....:|real)' $(ls -tr ${OUTPUT_DIR}/*.out)
|
|
|
@ -1,11 +0,0 @@
|
||||||
# Test spec file: used from ./run-test-distros.sh, will run
|
|
||||||
# each distro in $DISTROS overloading main kubespray ansible-playbook run
|
|
||||||
# Get all DISTROS from distro.yaml (shame no yaml parsing, but nuff anyway)
|
|
||||||
# DISTROS="${*:-$(egrep -o '^ \w+' group_vars/all/distro.yaml|paste -s)}"
|
|
||||||
DISTROS=(debian ubuntu centos fedora)
|
|
||||||
|
|
||||||
# Each line below will be added as --extra-vars to main playbook run
|
|
||||||
EXTRAS=(
|
|
||||||
'kube_network_plugin=calico'
|
|
||||||
'kube_network_plugin=weave'
|
|
||||||
)
|
|
|
@ -1,6 +0,0 @@
|
||||||
DISTROS=(debian centos)
|
|
||||||
NETCHECKER_HOST=${NODES[0]}
|
|
||||||
EXTRAS=(
|
|
||||||
'kube_network_plugin=kube-router {"kube_router_run_service_proxy":false}'
|
|
||||||
'kube_network_plugin=kube-router {"kube_router_run_service_proxy":true}'
|
|
||||||
)
|
|
|
@ -1,8 +0,0 @@
|
||||||
DISTROS=(debian centos)
|
|
||||||
EXTRAS=(
|
|
||||||
'kube_network_plugin=calico {}'
|
|
||||||
'kube_network_plugin=canal {}'
|
|
||||||
'kube_network_plugin=cilium {}'
|
|
||||||
'kube_network_plugin=flannel {}'
|
|
||||||
'kube_network_plugin=weave {}'
|
|
||||||
)
|
|
|
@ -1,480 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
# implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
# Usage: inventory.py ip1 [ip2 ...]
|
|
||||||
# Examples: inventory.py 10.10.1.3 10.10.1.4 10.10.1.5
|
|
||||||
#
|
|
||||||
# Advanced usage:
|
|
||||||
# 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 by id: inventory.py -node1
|
|
||||||
#
|
|
||||||
# Load a YAML or JSON file with inventory data: inventory.py load hosts.yaml
|
|
||||||
# YAML file should be in the following format:
|
|
||||||
# group1:
|
|
||||||
# host1:
|
|
||||||
# ip: X.X.X.X
|
|
||||||
# var: val
|
|
||||||
# group2:
|
|
||||||
# host2:
|
|
||||||
# ip: X.X.X.X
|
|
||||||
|
|
||||||
from collections import OrderedDict
|
|
||||||
from ipaddress import ip_address
|
|
||||||
from ruamel.yaml import YAML
|
|
||||||
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import subprocess
|
|
||||||
import sys
|
|
||||||
|
|
||||||
ROLES = ['all', 'kube_control_plane', 'kube_node', 'etcd', 'k8s_cluster',
|
|
||||||
'calico_rr']
|
|
||||||
PROTECTED_NAMES = ROLES
|
|
||||||
AVAILABLE_COMMANDS = ['help', 'print_cfg', 'print_ips', 'print_hostnames',
|
|
||||||
'load', 'add']
|
|
||||||
_boolean_states = {'1': True, 'yes': True, 'true': True, 'on': True,
|
|
||||||
'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):
|
|
||||||
value = os.environ.get(name, '')
|
|
||||||
return _boolean_states.get(value.lower(), default)
|
|
||||||
|
|
||||||
# Configurable as shell vars start
|
|
||||||
|
|
||||||
|
|
||||||
CONFIG_FILE = os.environ.get("CONFIG_FILE", "./inventory/sample/hosts.yaml")
|
|
||||||
# Remove the reference of KUBE_MASTERS after some deprecation cycles.
|
|
||||||
KUBE_CONTROL_HOSTS = int(os.environ.get("KUBE_CONTROL_HOSTS",
|
|
||||||
os.environ.get("KUBE_MASTERS", 2)))
|
|
||||||
# Reconfigures cluster distribution at scale
|
|
||||||
SCALE_THRESHOLD = int(os.environ.get("SCALE_THRESHOLD", 50))
|
|
||||||
MASSIVE_SCALE_THRESHOLD = int(os.environ.get("MASSIVE_SCALE_THRESHOLD", 200))
|
|
||||||
|
|
||||||
DEBUG = get_var_as_bool("DEBUG", True)
|
|
||||||
HOST_PREFIX = os.environ.get("HOST_PREFIX", "node")
|
|
||||||
USE_REAL_HOSTNAME = get_var_as_bool("USE_REAL_HOSTNAME", False)
|
|
||||||
|
|
||||||
# Configurable as shell vars end
|
|
||||||
|
|
||||||
|
|
||||||
class KubesprayInventory(object):
|
|
||||||
|
|
||||||
def __init__(self, changed_hosts=None, config_file=None):
|
|
||||||
self.config_file = config_file
|
|
||||||
self.yaml_config = {}
|
|
||||||
loadPreviousConfig = False
|
|
||||||
printHostnames = False
|
|
||||||
# See whether there are any commands to process
|
|
||||||
if changed_hosts and changed_hosts[0] in AVAILABLE_COMMANDS:
|
|
||||||
if changed_hosts[0] == "add":
|
|
||||||
loadPreviousConfig = True
|
|
||||||
changed_hosts = changed_hosts[1:]
|
|
||||||
elif changed_hosts[0] == "print_hostnames":
|
|
||||||
loadPreviousConfig = True
|
|
||||||
printHostnames = True
|
|
||||||
else:
|
|
||||||
self.parse_command(changed_hosts[0], changed_hosts[1:])
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
# If the user wants to remove a node, we need to load the config anyway
|
|
||||||
if changed_hosts and changed_hosts[0][0] == "-":
|
|
||||||
loadPreviousConfig = True
|
|
||||||
|
|
||||||
if self.config_file and loadPreviousConfig: # Load previous YAML file
|
|
||||||
try:
|
|
||||||
self.hosts_file = open(config_file, 'r')
|
|
||||||
self.yaml_config = yaml.load(self.hosts_file)
|
|
||||||
except OSError as e:
|
|
||||||
# I am assuming we are catching "cannot open file" exceptions
|
|
||||||
print(e)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if printHostnames:
|
|
||||||
self.print_hostnames()
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
self.ensure_required_groups(ROLES)
|
|
||||||
|
|
||||||
if changed_hosts:
|
|
||||||
changed_hosts = self.range2ips(changed_hosts)
|
|
||||||
self.hosts = self.build_hostnames(changed_hosts,
|
|
||||||
loadPreviousConfig)
|
|
||||||
self.purge_invalid_hosts(self.hosts.keys(), PROTECTED_NAMES)
|
|
||||||
self.set_all(self.hosts)
|
|
||||||
self.set_k8s_cluster()
|
|
||||||
etcd_hosts_count = 3 if len(self.hosts.keys()) >= 3 else 1
|
|
||||||
self.set_etcd(list(self.hosts.keys())[:etcd_hosts_count])
|
|
||||||
if len(self.hosts) >= SCALE_THRESHOLD:
|
|
||||||
self.set_kube_control_plane(list(self.hosts.keys())[
|
|
||||||
etcd_hosts_count:(etcd_hosts_count + KUBE_CONTROL_HOSTS)])
|
|
||||||
else:
|
|
||||||
self.set_kube_control_plane(
|
|
||||||
list(self.hosts.keys())[:KUBE_CONTROL_HOSTS])
|
|
||||||
self.set_kube_node(self.hosts.keys())
|
|
||||||
if len(self.hosts) >= SCALE_THRESHOLD:
|
|
||||||
self.set_calico_rr(list(self.hosts.keys())[:etcd_hosts_count])
|
|
||||||
else: # Show help if no options
|
|
||||||
self.show_help()
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
self.write_config(self.config_file)
|
|
||||||
|
|
||||||
def write_config(self, config_file):
|
|
||||||
if config_file:
|
|
||||||
with open(self.config_file, 'w') as f:
|
|
||||||
yaml.dump(self.yaml_config, f)
|
|
||||||
|
|
||||||
else:
|
|
||||||
print("WARNING: Unable to save config. Make sure you set "
|
|
||||||
"CONFIG_FILE env var.")
|
|
||||||
|
|
||||||
def debug(self, msg):
|
|
||||||
if DEBUG:
|
|
||||||
print("DEBUG: {0}".format(msg))
|
|
||||||
|
|
||||||
def get_ip_from_opts(self, optstring):
|
|
||||||
if 'ip' in optstring:
|
|
||||||
return optstring['ip']
|
|
||||||
else:
|
|
||||||
raise ValueError("IP parameter not found in options")
|
|
||||||
|
|
||||||
def ensure_required_groups(self, groups):
|
|
||||||
for group in groups:
|
|
||||||
if group == 'all':
|
|
||||||
self.debug("Adding group {0}".format(group))
|
|
||||||
if group not in self.yaml_config:
|
|
||||||
all_dict = OrderedDict([('hosts', OrderedDict({})),
|
|
||||||
('children', OrderedDict({}))])
|
|
||||||
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):
|
|
||||||
'''Returns integer host ID (without padding) from a given hostname.'''
|
|
||||||
try:
|
|
||||||
short_hostname = host.split('.')[0]
|
|
||||||
return int(re.findall("\\d+$", short_hostname)[-1])
|
|
||||||
except IndexError:
|
|
||||||
raise ValueError("Host name must end in an integer")
|
|
||||||
|
|
||||||
# Keeps already specified hosts,
|
|
||||||
# and adds or removes the hosts provided as an argument
|
|
||||||
def build_hostnames(self, changed_hosts, loadPreviousConfig=False):
|
|
||||||
existing_hosts = OrderedDict()
|
|
||||||
highest_host_id = 0
|
|
||||||
# Load already existing hosts from the YAML
|
|
||||||
if loadPreviousConfig:
|
|
||||||
try:
|
|
||||||
for host in self.yaml_config['all']['hosts']:
|
|
||||||
# Read configuration of an existing host
|
|
||||||
hostConfig = self.yaml_config['all']['hosts'][host]
|
|
||||||
existing_hosts[host] = hostConfig
|
|
||||||
# If the existing host seems
|
|
||||||
# to have been created automatically, detect its ID
|
|
||||||
if host.startswith(HOST_PREFIX):
|
|
||||||
host_id = self.get_host_id(host)
|
|
||||||
if host_id > highest_host_id:
|
|
||||||
highest_host_id = host_id
|
|
||||||
except Exception as e:
|
|
||||||
# I am assuming we are catching automatically
|
|
||||||
# created hosts without IDs
|
|
||||||
print(e)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# FIXME(mattymo): Fix condition where delete then add reuses highest id
|
|
||||||
next_host_id = highest_host_id + 1
|
|
||||||
next_host = ""
|
|
||||||
|
|
||||||
all_hosts = existing_hosts.copy()
|
|
||||||
for host in changed_hosts:
|
|
||||||
# Delete the host from config the hostname/IP has a "-" prefix
|
|
||||||
if host[0] == "-":
|
|
||||||
realhost = host[1:]
|
|
||||||
if self.exists_hostname(all_hosts, realhost):
|
|
||||||
self.debug("Marked {0} for deletion.".format(realhost))
|
|
||||||
all_hosts.pop(realhost)
|
|
||||||
elif self.exists_ip(all_hosts, realhost):
|
|
||||||
self.debug("Marked {0} for deletion.".format(realhost))
|
|
||||||
self.delete_host_by_ip(all_hosts, realhost)
|
|
||||||
# Host/Argument starts with a digit,
|
|
||||||
# then we assume its an IP address
|
|
||||||
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):
|
|
||||||
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
|
|
||||||
|
|
||||||
if USE_REAL_HOSTNAME:
|
|
||||||
cmd = ("ssh -oStrictHostKeyChecking=no "
|
|
||||||
+ access_ip + " 'hostname -s'")
|
|
||||||
next_host = subprocess.check_output(cmd, shell=True)
|
|
||||||
next_host = next_host.strip().decode('ascii')
|
|
||||||
else:
|
|
||||||
# Generates a hostname because we have only an IP address
|
|
||||||
next_host = "{0}{1}".format(HOST_PREFIX, next_host_id)
|
|
||||||
next_host_id += 1
|
|
||||||
# Uses automatically generated node name
|
|
||||||
# in case we dont provide it.
|
|
||||||
all_hosts[next_host] = {'ansible_host': access_ip,
|
|
||||||
'ip': ip,
|
|
||||||
'access_ip': access_ip}
|
|
||||||
# Host/Argument starts with a letter, then we assume its a hostname
|
|
||||||
elif host[0].isalpha():
|
|
||||||
if ',' in host:
|
|
||||||
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
|
|
||||||
|
|
||||||
# Expand IP ranges into individual addresses
|
|
||||||
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('-') or host[0].isalpha()):
|
|
||||||
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):
|
|
||||||
return hostname in existing_hosts.keys()
|
|
||||||
|
|
||||||
def exists_ip(self, existing_hosts, ip):
|
|
||||||
for host_opts in existing_hosts.values():
|
|
||||||
if ip == self.get_ip_from_opts(host_opts):
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def delete_host_by_ip(self, existing_hosts, ip):
|
|
||||||
for hostname, host_opts in existing_hosts.items():
|
|
||||||
if ip == self.get_ip_from_opts(host_opts):
|
|
||||||
del existing_hosts[hostname]
|
|
||||||
return
|
|
||||||
raise ValueError("Unable to find host by IP: {0}".format(ip))
|
|
||||||
|
|
||||||
def purge_invalid_hosts(self, hostnames, protected_names=[]):
|
|
||||||
for role in self.yaml_config['all']['children']:
|
|
||||||
if role != 'k8s_cluster' and self.yaml_config['all']['children'][role]['hosts']: # noqa
|
|
||||||
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:
|
|
||||||
self.debug("Host {0} removed from role all".format(host))
|
|
||||||
del self.yaml_config['all']['hosts'][host]
|
|
||||||
|
|
||||||
def add_host_to_group(self, group, host, opts=""):
|
|
||||||
self.debug("adding host {0} to group {1}".format(host, group))
|
|
||||||
if group == 'all':
|
|
||||||
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_control_plane(self, hosts):
|
|
||||||
for host in hosts:
|
|
||||||
self.add_host_to_group('kube_control_plane', host)
|
|
||||||
|
|
||||||
def set_all(self, hosts):
|
|
||||||
for host, opts in hosts.items():
|
|
||||||
self.add_host_to_group('all', host, opts)
|
|
||||||
|
|
||||||
def set_k8s_cluster(self):
|
|
||||||
k8s_cluster = {'children': {'kube_control_plane': None,
|
|
||||||
'kube_node': None}}
|
|
||||||
self.yaml_config['all']['children']['k8s_cluster'] = k8s_cluster
|
|
||||||
|
|
||||||
def set_calico_rr(self, hosts):
|
|
||||||
for host in hosts:
|
|
||||||
if host in self.yaml_config['all']['children']['kube_control_plane']: # noqa
|
|
||||||
self.debug("Not adding {0} to calico_rr group because it "
|
|
||||||
"conflicts with kube_control_plane "
|
|
||||||
"group".format(host))
|
|
||||||
continue
|
|
||||||
if host in self.yaml_config['all']['children']['kube_node']:
|
|
||||||
self.debug("Not adding {0} to calico_rr group because it "
|
|
||||||
"conflicts with kube_node group".format(host))
|
|
||||||
continue
|
|
||||||
self.add_host_to_group('calico_rr', host)
|
|
||||||
|
|
||||||
def set_kube_node(self, hosts):
|
|
||||||
for host in hosts:
|
|
||||||
if len(self.yaml_config['all']['hosts']) >= SCALE_THRESHOLD:
|
|
||||||
if host in self.yaml_config['all']['children']['etcd']['hosts']: # noqa
|
|
||||||
self.debug("Not adding {0} to kube_node group because of "
|
|
||||||
"scale deployment and host is in etcd "
|
|
||||||
"group.".format(host))
|
|
||||||
continue
|
|
||||||
if len(self.yaml_config['all']['hosts']) >= MASSIVE_SCALE_THRESHOLD: # noqa
|
|
||||||
if host in self.yaml_config['all']['children']['kube_control_plane']['hosts']: # noqa
|
|
||||||
self.debug("Not adding {0} to kube_node group because of "
|
|
||||||
"scale deployment and host is in "
|
|
||||||
"kube_control_plane group.".format(host))
|
|
||||||
continue
|
|
||||||
self.add_host_to_group('kube_node', host)
|
|
||||||
|
|
||||||
def set_etcd(self, hosts):
|
|
||||||
for host in hosts:
|
|
||||||
self.add_host_to_group('etcd', host)
|
|
||||||
|
|
||||||
def load_file(self, files=None):
|
|
||||||
'''Directly loads JSON to inventory.'''
|
|
||||||
|
|
||||||
if not files:
|
|
||||||
raise Exception("No input file specified.")
|
|
||||||
|
|
||||||
import json
|
|
||||||
|
|
||||||
for filename in list(files):
|
|
||||||
# Try JSON
|
|
||||||
try:
|
|
||||||
with open(filename, 'r') as f:
|
|
||||||
data = json.load(f)
|
|
||||||
except ValueError:
|
|
||||||
raise Exception("Cannot read %s as JSON, or CSV", filename)
|
|
||||||
|
|
||||||
self.ensure_required_groups(ROLES)
|
|
||||||
self.set_k8s_cluster()
|
|
||||||
for group, hosts in data.items():
|
|
||||||
self.ensure_required_groups([group])
|
|
||||||
for host, opts in hosts.items():
|
|
||||||
optstring = {'ansible_host': opts['ip'],
|
|
||||||
'ip': opts['ip'],
|
|
||||||
'access_ip': opts['ip']}
|
|
||||||
self.add_host_to_group('all', host, optstring)
|
|
||||||
self.add_host_to_group(group, host)
|
|
||||||
self.write_config(self.config_file)
|
|
||||||
|
|
||||||
def parse_command(self, command, args=None):
|
|
||||||
if command == 'help':
|
|
||||||
self.show_help()
|
|
||||||
elif command == 'print_cfg':
|
|
||||||
self.print_config()
|
|
||||||
elif command == 'print_ips':
|
|
||||||
self.print_ips()
|
|
||||||
elif command == 'print_hostnames':
|
|
||||||
self.print_hostnames()
|
|
||||||
elif command == 'load':
|
|
||||||
self.load_file(args)
|
|
||||||
else:
|
|
||||||
raise Exception("Invalid command specified.")
|
|
||||||
|
|
||||||
def show_help(self):
|
|
||||||
help_text = '''Usage: inventory.py ip1 [ip2 ...]
|
|
||||||
Examples: inventory.py 10.10.1.3 10.10.1.4 10.10.1.5
|
|
||||||
|
|
||||||
Available commands:
|
|
||||||
help - Display this message
|
|
||||||
print_cfg - Write inventory file to stdout
|
|
||||||
print_ips - Write a space-delimited list of IPs from "all" group
|
|
||||||
print_hostnames - Write a space-delimited list of Hostnames from "all" group
|
|
||||||
add - Adds specified hosts into an already existing inventory
|
|
||||||
|
|
||||||
Advanced usage:
|
|
||||||
Create new or overwrite old inventory file: inventory.py 10.10.1.5
|
|
||||||
Add another host after initial creation: inventory.py add 10.10.1.6
|
|
||||||
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 by id: inventory.py -node1
|
|
||||||
|
|
||||||
Configurable env vars:
|
|
||||||
DEBUG Enable debug printing. Default: True
|
|
||||||
CONFIG_FILE File to write config to Default: ./inventory/sample/hosts.yaml
|
|
||||||
HOST_PREFIX Host prefix for generated hosts. Default: node
|
|
||||||
KUBE_CONTROL_HOSTS Set the number of kube-control-planes. Default: 2
|
|
||||||
SCALE_THRESHOLD Separate ETCD role if # of nodes >= 50
|
|
||||||
MASSIVE_SCALE_THRESHOLD Separate K8s control-plane and ETCD if # of nodes >= 200
|
|
||||||
''' # noqa
|
|
||||||
print(help_text)
|
|
||||||
|
|
||||||
def print_config(self):
|
|
||||||
yaml.dump(self.yaml_config, sys.stdout)
|
|
||||||
|
|
||||||
def print_hostnames(self):
|
|
||||||
print(' '.join(self.yaml_config['all']['hosts'].keys()))
|
|
||||||
|
|
||||||
def print_ips(self):
|
|
||||||
ips = []
|
|
||||||
for host, opts in self.yaml_config['all']['hosts'].items():
|
|
||||||
ips.append(self.get_ip_from_opts(opts))
|
|
||||||
print(' '.join(ips))
|
|
||||||
|
|
||||||
|
|
||||||
def main(argv=None):
|
|
||||||
if not argv:
|
|
||||||
argv = sys.argv[1:]
|
|
||||||
KubesprayInventory(argv, CONFIG_FILE)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
|
@ -1,3 +0,0 @@
|
||||||
configparser>=3.3.0
|
|
||||||
ruamel.yaml>=0.15.88
|
|
||||||
ipaddress
|
|
|
@ -1,3 +0,0 @@
|
||||||
[metadata]
|
|
||||||
name = kubespray-inventory-builder
|
|
||||||
version = 0.1
|
|
|
@ -1,29 +0,0 @@
|
||||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
# implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
|
|
||||||
import setuptools
|
|
||||||
|
|
||||||
# In python < 2.7.4, a lazy loading of package `pbr` will break
|
|
||||||
# setuptools if some other modules registered functions in `atexit`.
|
|
||||||
# solution from: http://bugs.python.org/issue15881#msg170215
|
|
||||||
try:
|
|
||||||
import multiprocessing # noqa
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
setuptools.setup(
|
|
||||||
setup_requires=[],
|
|
||||||
pbr=False)
|
|
|
@ -1,3 +0,0 @@
|
||||||
hacking>=0.10.2
|
|
||||||
pytest>=2.8.0
|
|
||||||
mock>=1.3.0
|
|
|
@ -1,595 +0,0 @@
|
||||||
# Copyright 2016 Mirantis, Inc.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
||||||
# not use this file except in compliance with the License. You may obtain
|
|
||||||
# a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
||||||
# License for the specific language governing permissions and limitations
|
|
||||||
# under the License.
|
|
||||||
|
|
||||||
import inventory
|
|
||||||
from io import StringIO
|
|
||||||
import unittest
|
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
from collections import OrderedDict
|
|
||||||
import sys
|
|
||||||
|
|
||||||
path = "./contrib/inventory_builder/"
|
|
||||||
if path not in sys.path:
|
|
||||||
sys.path.append(path)
|
|
||||||
|
|
||||||
import inventory # noqa
|
|
||||||
|
|
||||||
|
|
||||||
class TestInventoryPrintHostnames(unittest.TestCase):
|
|
||||||
|
|
||||||
@mock.patch('ruamel.yaml.YAML.load')
|
|
||||||
def test_print_hostnames(self, load_mock):
|
|
||||||
mock_io = mock.mock_open(read_data='')
|
|
||||||
load_mock.return_value = OrderedDict({'all': {'hosts': {
|
|
||||||
'node1': {'ansible_host': '10.90.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'access_ip': '10.90.0.2'},
|
|
||||||
'node2': {'ansible_host': '10.90.0.3',
|
|
||||||
'ip': '10.90.0.3',
|
|
||||||
'access_ip': '10.90.0.3'}}}})
|
|
||||||
with mock.patch('builtins.open', mock_io):
|
|
||||||
with self.assertRaises(SystemExit) as cm:
|
|
||||||
with mock.patch('sys.stdout', new_callable=StringIO) as stdout:
|
|
||||||
inventory.KubesprayInventory(
|
|
||||||
changed_hosts=["print_hostnames"],
|
|
||||||
config_file="file")
|
|
||||||
self.assertEqual("node1 node2\n", stdout.getvalue())
|
|
||||||
self.assertEqual(cm.exception.code, 0)
|
|
||||||
|
|
||||||
|
|
||||||
class TestInventory(unittest.TestCase):
|
|
||||||
@mock.patch('inventory.sys')
|
|
||||||
def setUp(self, sys_mock):
|
|
||||||
sys_mock.exit = mock.Mock()
|
|
||||||
super(TestInventory, self).setUp()
|
|
||||||
self.data = ['10.90.3.2', '10.90.3.3', '10.90.3.4']
|
|
||||||
self.inv = inventory.KubesprayInventory()
|
|
||||||
|
|
||||||
def test_get_ip_from_opts(self):
|
|
||||||
optstring = {'ansible_host': '10.90.3.2',
|
|
||||||
'ip': '10.90.3.2',
|
|
||||||
'access_ip': '10.90.3.2'}
|
|
||||||
expected = "10.90.3.2"
|
|
||||||
result = self.inv.get_ip_from_opts(optstring)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_get_ip_from_opts_invalid(self):
|
|
||||||
optstring = "notanaddr=value something random!chars:D"
|
|
||||||
self.assertRaisesRegex(ValueError, "IP parameter not found",
|
|
||||||
self.inv.get_ip_from_opts, optstring)
|
|
||||||
|
|
||||||
def test_ensure_required_groups(self):
|
|
||||||
groups = ['group1', 'group2']
|
|
||||||
self.inv.ensure_required_groups(groups)
|
|
||||||
for group in groups:
|
|
||||||
self.assertIn(group, self.inv.yaml_config['all']['children'])
|
|
||||||
|
|
||||||
def test_get_host_id(self):
|
|
||||||
hostnames = ['node99', 'no99de01', '01node01', 'node1.domain',
|
|
||||||
'node3.xyz123.aaa']
|
|
||||||
expected = [99, 1, 1, 1, 3]
|
|
||||||
for hostname, expected in zip(hostnames, expected):
|
|
||||||
result = self.inv.get_host_id(hostname)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_get_host_id_invalid(self):
|
|
||||||
bad_hostnames = ['node', 'no99de', '01node', 'node.111111']
|
|
||||||
for hostname in bad_hostnames:
|
|
||||||
self.assertRaisesRegex(ValueError, "Host name must end in an",
|
|
||||||
self.inv.get_host_id, hostname)
|
|
||||||
|
|
||||||
def test_build_hostnames_add_duplicate(self):
|
|
||||||
changed_hosts = ['10.90.0.2']
|
|
||||||
expected = OrderedDict([('node3',
|
|
||||||
{'ansible_host': '10.90.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'access_ip': '10.90.0.2'})])
|
|
||||||
self.inv.yaml_config['all']['hosts'] = expected
|
|
||||||
result = self.inv.build_hostnames(changed_hosts, True)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_build_hostnames_add_two(self):
|
|
||||||
changed_hosts = ['10.90.0.2', '10.90.0.3']
|
|
||||||
expected = OrderedDict([
|
|
||||||
('node1', {'ansible_host': '10.90.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'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.yaml_config['all']['hosts'] = OrderedDict()
|
|
||||||
result = self.inv.build_hostnames(changed_hosts)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_build_hostnames_add_three(self):
|
|
||||||
changed_hosts = ['10.90.0.2', '10.90.0.3', '10.90.0.4']
|
|
||||||
expected = OrderedDict([
|
|
||||||
('node1', {'ansible_host': '10.90.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'access_ip': '10.90.0.2'}),
|
|
||||||
('node2', {'ansible_host': '10.90.0.3',
|
|
||||||
'ip': '10.90.0.3',
|
|
||||||
'access_ip': '10.90.0.3'}),
|
|
||||||
('node3', {'ansible_host': '10.90.0.4',
|
|
||||||
'ip': '10.90.0.4',
|
|
||||||
'access_ip': '10.90.0.4'})])
|
|
||||||
result = self.inv.build_hostnames(changed_hosts)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_build_hostnames_add_one(self):
|
|
||||||
changed_hosts = ['10.90.0.2']
|
|
||||||
expected = OrderedDict([('node1',
|
|
||||||
{'ansible_host': '10.90.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'access_ip': '10.90.0.2'})])
|
|
||||||
result = self.inv.build_hostnames(changed_hosts)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_build_hostnames_delete_first(self):
|
|
||||||
changed_hosts = ['-10.90.0.2']
|
|
||||||
existing_hosts = OrderedDict([
|
|
||||||
('node1', {'ansible_host': '10.90.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'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.yaml_config['all']['hosts'] = existing_hosts
|
|
||||||
expected = OrderedDict([
|
|
||||||
('node2', {'ansible_host': '10.90.0.3',
|
|
||||||
'ip': '10.90.0.3',
|
|
||||||
'access_ip': '10.90.0.3'})])
|
|
||||||
result = self.inv.build_hostnames(changed_hosts, True)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_build_hostnames_delete_by_hostname(self):
|
|
||||||
changed_hosts = ['-node1']
|
|
||||||
existing_hosts = OrderedDict([
|
|
||||||
('node1', {'ansible_host': '10.90.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'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.yaml_config['all']['hosts'] = existing_hosts
|
|
||||||
expected = OrderedDict([
|
|
||||||
('node2', {'ansible_host': '10.90.0.3',
|
|
||||||
'ip': '10.90.0.3',
|
|
||||||
'access_ip': '10.90.0.3'})])
|
|
||||||
result = self.inv.build_hostnames(changed_hosts, True)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_exists_hostname_positive(self):
|
|
||||||
hostname = 'node1'
|
|
||||||
expected = True
|
|
||||||
existing_hosts = OrderedDict([
|
|
||||||
('node1', {'ansible_host': '10.90.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'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)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_exists_hostname_negative(self):
|
|
||||||
hostname = 'node99'
|
|
||||||
expected = False
|
|
||||||
existing_hosts = OrderedDict([
|
|
||||||
('node1', {'ansible_host': '10.90.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'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)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_exists_ip_positive(self):
|
|
||||||
ip = '10.90.0.2'
|
|
||||||
expected = True
|
|
||||||
existing_hosts = OrderedDict([
|
|
||||||
('node1', {'ansible_host': '10.90.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'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)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_exists_ip_negative(self):
|
|
||||||
ip = '10.90.0.200'
|
|
||||||
expected = False
|
|
||||||
existing_hosts = OrderedDict([
|
|
||||||
('node1', {'ansible_host': '10.90.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'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)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_delete_host_by_ip_positive(self):
|
|
||||||
ip = '10.90.0.2'
|
|
||||||
expected = OrderedDict([
|
|
||||||
('node2', {'ansible_host': '10.90.0.3',
|
|
||||||
'ip': '10.90.0.3',
|
|
||||||
'access_ip': '10.90.0.3'})])
|
|
||||||
existing_hosts = OrderedDict([
|
|
||||||
('node1', {'ansible_host': '10.90.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'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.assertEqual(expected, existing_hosts)
|
|
||||||
|
|
||||||
def test_delete_host_by_ip_negative(self):
|
|
||||||
ip = '10.90.0.200'
|
|
||||||
existing_hosts = OrderedDict([
|
|
||||||
('node1', {'ansible_host': '10.90.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'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.assertRaisesRegex(ValueError, "Unable to find host",
|
|
||||||
self.inv.delete_host_by_ip, existing_hosts, ip)
|
|
||||||
|
|
||||||
def test_purge_invalid_hosts(self):
|
|
||||||
proper_hostnames = ['node1', 'node2']
|
|
||||||
bad_host = 'doesnotbelong2'
|
|
||||||
existing_hosts = OrderedDict([
|
|
||||||
('node1', {'ansible_host': '10.90.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'access_ip': '10.90.0.2'}),
|
|
||||||
('node2', {'ansible_host': '10.90.0.3',
|
|
||||||
'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.assertNotIn(
|
|
||||||
bad_host, self.inv.yaml_config['all']['hosts'].keys())
|
|
||||||
|
|
||||||
def test_add_host_to_group(self):
|
|
||||||
group = 'etcd'
|
|
||||||
host = 'node1'
|
|
||||||
opts = {'ip': '10.90.0.2'}
|
|
||||||
|
|
||||||
self.inv.add_host_to_group(group, host, opts)
|
|
||||||
self.assertEqual(
|
|
||||||
self.inv.yaml_config['all']['children'][group]['hosts'].get(host),
|
|
||||||
None)
|
|
||||||
|
|
||||||
def test_set_kube_control_plane(self):
|
|
||||||
group = 'kube_control_plane'
|
|
||||||
host = 'node1'
|
|
||||||
|
|
||||||
self.inv.set_kube_control_plane([host])
|
|
||||||
self.assertIn(
|
|
||||||
host, self.inv.yaml_config['all']['children'][group]['hosts'])
|
|
||||||
|
|
||||||
def test_set_all(self):
|
|
||||||
hosts = OrderedDict([
|
|
||||||
('node1', 'opt1'),
|
|
||||||
('node2', 'opt2')])
|
|
||||||
|
|
||||||
self.inv.set_all(hosts)
|
|
||||||
for host, opt in hosts.items():
|
|
||||||
self.assertEqual(
|
|
||||||
self.inv.yaml_config['all']['hosts'].get(host), opt)
|
|
||||||
|
|
||||||
def test_set_k8s_cluster(self):
|
|
||||||
group = 'k8s_cluster'
|
|
||||||
expected_hosts = ['kube_node', 'kube_control_plane']
|
|
||||||
|
|
||||||
self.inv.set_k8s_cluster()
|
|
||||||
for host in expected_hosts:
|
|
||||||
self.assertIn(
|
|
||||||
host,
|
|
||||||
self.inv.yaml_config['all']['children'][group]['children'])
|
|
||||||
|
|
||||||
def test_set_kube_node(self):
|
|
||||||
group = 'kube_node'
|
|
||||||
host = 'node1'
|
|
||||||
|
|
||||||
self.inv.set_kube_node([host])
|
|
||||||
self.assertIn(
|
|
||||||
host, self.inv.yaml_config['all']['children'][group]['hosts'])
|
|
||||||
|
|
||||||
def test_set_etcd(self):
|
|
||||||
group = 'etcd'
|
|
||||||
host = 'node1'
|
|
||||||
|
|
||||||
self.inv.set_etcd([host])
|
|
||||||
self.assertIn(
|
|
||||||
host, self.inv.yaml_config['all']['children'][group]['hosts'])
|
|
||||||
|
|
||||||
def test_scale_scenario_one(self):
|
|
||||||
num_nodes = 50
|
|
||||||
hosts = OrderedDict()
|
|
||||||
|
|
||||||
for hostid in range(1, num_nodes+1):
|
|
||||||
hosts["node" + str(hostid)] = ""
|
|
||||||
|
|
||||||
self.inv.set_all(hosts)
|
|
||||||
self.inv.set_etcd(list(hosts.keys())[0:3])
|
|
||||||
self.inv.set_kube_control_plane(list(hosts.keys())[0:2])
|
|
||||||
self.inv.set_kube_node(hosts.keys())
|
|
||||||
for h in range(3):
|
|
||||||
self.assertFalse(
|
|
||||||
list(hosts.keys())[h] in
|
|
||||||
self.inv.yaml_config['all']['children']['kube_node']['hosts'])
|
|
||||||
|
|
||||||
def test_scale_scenario_two(self):
|
|
||||||
num_nodes = 500
|
|
||||||
hosts = OrderedDict()
|
|
||||||
|
|
||||||
for hostid in range(1, num_nodes+1):
|
|
||||||
hosts["node" + str(hostid)] = ""
|
|
||||||
|
|
||||||
self.inv.set_all(hosts)
|
|
||||||
self.inv.set_etcd(list(hosts.keys())[0:3])
|
|
||||||
self.inv.set_kube_control_plane(list(hosts.keys())[3:5])
|
|
||||||
self.inv.set_kube_node(hosts.keys())
|
|
||||||
for h in range(5):
|
|
||||||
self.assertFalse(
|
|
||||||
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_create_with_one_different_ips(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_create_with_two_different_ips(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'})])
|
|
||||||
result = self.inv.build_hostnames(changed_hosts)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_build_hostnames_create_with_three_different_ips(self):
|
|
||||||
changed_hosts = ['10.90.0.2,192.168.0.2',
|
|
||||||
'10.90.0.3,192.168.0.3',
|
|
||||||
'10.90.0.4,192.168.0.4']
|
|
||||||
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'}),
|
|
||||||
('node3', {'ansible_host': '192.168.0.4',
|
|
||||||
'ip': '10.90.0.4',
|
|
||||||
'access_ip': '192.168.0.4'})])
|
|
||||||
result = self.inv.build_hostnames(changed_hosts)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_build_hostnames_overwrite_one_with_different_ips(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'})])
|
|
||||||
existing = OrderedDict([('node5',
|
|
||||||
{'ansible_host': '192.168.0.5',
|
|
||||||
'ip': '10.90.0.5',
|
|
||||||
'access_ip': '192.168.0.5'})])
|
|
||||||
self.inv.yaml_config['all']['hosts'] = existing
|
|
||||||
result = self.inv.build_hostnames(changed_hosts)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_build_hostnames_overwrite_three_with_different_ips(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'})])
|
|
||||||
existing = OrderedDict([
|
|
||||||
('node3', {'ansible_host': '192.168.0.3',
|
|
||||||
'ip': '10.90.0.3',
|
|
||||||
'access_ip': '192.168.0.3'}),
|
|
||||||
('node4', {'ansible_host': '192.168.0.4',
|
|
||||||
'ip': '10.90.0.4',
|
|
||||||
'access_ip': '192.168.0.4'}),
|
|
||||||
('node5', {'ansible_host': '192.168.0.5',
|
|
||||||
'ip': '10.90.0.5',
|
|
||||||
'access_ip': '192.168.0.5'})])
|
|
||||||
self.inv.yaml_config['all']['hosts'] = existing
|
|
||||||
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([('node3',
|
|
||||||
{'ansible_host': '192.168.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'access_ip': '192.168.0.2'})])
|
|
||||||
existing = expected
|
|
||||||
self.inv.yaml_config['all']['hosts'] = existing
|
|
||||||
result = self.inv.build_hostnames(changed_hosts, True)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_build_hostnames_add_two_different_ips_into_one_existing(self):
|
|
||||||
changed_hosts = ['10.90.0.3,192.168.0.3', '10.90.0.4,192.168.0.4']
|
|
||||||
expected = OrderedDict([
|
|
||||||
('node2', {'ansible_host': '192.168.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'access_ip': '192.168.0.2'}),
|
|
||||||
('node3', {'ansible_host': '192.168.0.3',
|
|
||||||
'ip': '10.90.0.3',
|
|
||||||
'access_ip': '192.168.0.3'}),
|
|
||||||
('node4', {'ansible_host': '192.168.0.4',
|
|
||||||
'ip': '10.90.0.4',
|
|
||||||
'access_ip': '192.168.0.4'})])
|
|
||||||
|
|
||||||
existing = OrderedDict([
|
|
||||||
('node2', {'ansible_host': '192.168.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'access_ip': '192.168.0.2'})])
|
|
||||||
self.inv.yaml_config['all']['hosts'] = existing
|
|
||||||
result = self.inv.build_hostnames(changed_hosts, True)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_build_hostnames_add_two_different_ips_into_two_existing(self):
|
|
||||||
changed_hosts = ['10.90.0.4,192.168.0.4', '10.90.0.5,192.168.0.5']
|
|
||||||
expected = OrderedDict([
|
|
||||||
('node2', {'ansible_host': '192.168.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'access_ip': '192.168.0.2'}),
|
|
||||||
('node3', {'ansible_host': '192.168.0.3',
|
|
||||||
'ip': '10.90.0.3',
|
|
||||||
'access_ip': '192.168.0.3'}),
|
|
||||||
('node4', {'ansible_host': '192.168.0.4',
|
|
||||||
'ip': '10.90.0.4',
|
|
||||||
'access_ip': '192.168.0.4'}),
|
|
||||||
('node5', {'ansible_host': '192.168.0.5',
|
|
||||||
'ip': '10.90.0.5',
|
|
||||||
'access_ip': '192.168.0.5'})])
|
|
||||||
|
|
||||||
existing = OrderedDict([
|
|
||||||
('node2', {'ansible_host': '192.168.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'access_ip': '192.168.0.2'}),
|
|
||||||
('node3', {'ansible_host': '192.168.0.3',
|
|
||||||
'ip': '10.90.0.3',
|
|
||||||
'access_ip': '192.168.0.3'})])
|
|
||||||
self.inv.yaml_config['all']['hosts'] = existing
|
|
||||||
result = self.inv.build_hostnames(changed_hosts, True)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
def test_build_hostnames_add_two_different_ips_into_three_existing(self):
|
|
||||||
changed_hosts = ['10.90.0.5,192.168.0.5', '10.90.0.6,192.168.0.6']
|
|
||||||
expected = OrderedDict([
|
|
||||||
('node2', {'ansible_host': '192.168.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'access_ip': '192.168.0.2'}),
|
|
||||||
('node3', {'ansible_host': '192.168.0.3',
|
|
||||||
'ip': '10.90.0.3',
|
|
||||||
'access_ip': '192.168.0.3'}),
|
|
||||||
('node4', {'ansible_host': '192.168.0.4',
|
|
||||||
'ip': '10.90.0.4',
|
|
||||||
'access_ip': '192.168.0.4'}),
|
|
||||||
('node5', {'ansible_host': '192.168.0.5',
|
|
||||||
'ip': '10.90.0.5',
|
|
||||||
'access_ip': '192.168.0.5'}),
|
|
||||||
('node6', {'ansible_host': '192.168.0.6',
|
|
||||||
'ip': '10.90.0.6',
|
|
||||||
'access_ip': '192.168.0.6'})])
|
|
||||||
|
|
||||||
existing = OrderedDict([
|
|
||||||
('node2', {'ansible_host': '192.168.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'access_ip': '192.168.0.2'}),
|
|
||||||
('node3', {'ansible_host': '192.168.0.3',
|
|
||||||
'ip': '10.90.0.3',
|
|
||||||
'access_ip': '192.168.0.3'}),
|
|
||||||
('node4', {'ansible_host': '192.168.0.4',
|
|
||||||
'ip': '10.90.0.4',
|
|
||||||
'access_ip': '192.168.0.4'})])
|
|
||||||
self.inv.yaml_config['all']['hosts'] = existing
|
|
||||||
result = self.inv.build_hostnames(changed_hosts, True)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
# Add two IP addresses into a config that has
|
|
||||||
# three already defined IP addresses. One of the IP addresses
|
|
||||||
# is a duplicate.
|
|
||||||
def test_build_hostnames_add_two_duplicate_one_overlap(self):
|
|
||||||
changed_hosts = ['10.90.0.4,192.168.0.4', '10.90.0.5,192.168.0.5']
|
|
||||||
expected = OrderedDict([
|
|
||||||
('node2', {'ansible_host': '192.168.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'access_ip': '192.168.0.2'}),
|
|
||||||
('node3', {'ansible_host': '192.168.0.3',
|
|
||||||
'ip': '10.90.0.3',
|
|
||||||
'access_ip': '192.168.0.3'}),
|
|
||||||
('node4', {'ansible_host': '192.168.0.4',
|
|
||||||
'ip': '10.90.0.4',
|
|
||||||
'access_ip': '192.168.0.4'}),
|
|
||||||
('node5', {'ansible_host': '192.168.0.5',
|
|
||||||
'ip': '10.90.0.5',
|
|
||||||
'access_ip': '192.168.0.5'})])
|
|
||||||
|
|
||||||
existing = OrderedDict([
|
|
||||||
('node2', {'ansible_host': '192.168.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'access_ip': '192.168.0.2'}),
|
|
||||||
('node3', {'ansible_host': '192.168.0.3',
|
|
||||||
'ip': '10.90.0.3',
|
|
||||||
'access_ip': '192.168.0.3'}),
|
|
||||||
('node4', {'ansible_host': '192.168.0.4',
|
|
||||||
'ip': '10.90.0.4',
|
|
||||||
'access_ip': '192.168.0.4'})])
|
|
||||||
self.inv.yaml_config['all']['hosts'] = existing
|
|
||||||
result = self.inv.build_hostnames(changed_hosts, True)
|
|
||||||
self.assertEqual(expected, result)
|
|
||||||
|
|
||||||
# Add two duplicate IP addresses into a config that has
|
|
||||||
# three already defined IP addresses
|
|
||||||
def test_build_hostnames_add_two_duplicate_two_overlap(self):
|
|
||||||
changed_hosts = ['10.90.0.3,192.168.0.3', '10.90.0.4,192.168.0.4']
|
|
||||||
expected = OrderedDict([
|
|
||||||
('node2', {'ansible_host': '192.168.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'access_ip': '192.168.0.2'}),
|
|
||||||
('node3', {'ansible_host': '192.168.0.3',
|
|
||||||
'ip': '10.90.0.3',
|
|
||||||
'access_ip': '192.168.0.3'}),
|
|
||||||
('node4', {'ansible_host': '192.168.0.4',
|
|
||||||
'ip': '10.90.0.4',
|
|
||||||
'access_ip': '192.168.0.4'})])
|
|
||||||
|
|
||||||
existing = OrderedDict([
|
|
||||||
('node2', {'ansible_host': '192.168.0.2',
|
|
||||||
'ip': '10.90.0.2',
|
|
||||||
'access_ip': '192.168.0.2'}),
|
|
||||||
('node3', {'ansible_host': '192.168.0.3',
|
|
||||||
'ip': '10.90.0.3',
|
|
||||||
'access_ip': '192.168.0.3'}),
|
|
||||||
('node4', {'ansible_host': '192.168.0.4',
|
|
||||||
'ip': '10.90.0.4',
|
|
||||||
'access_ip': '192.168.0.4'})])
|
|
||||||
self.inv.yaml_config['all']['hosts'] = existing
|
|
||||||
result = self.inv.build_hostnames(changed_hosts, True)
|
|
||||||
self.assertEqual(expected, result)
|
|
|
@ -1,28 +0,0 @@
|
||||||
[tox]
|
|
||||||
minversion = 1.6
|
|
||||||
skipsdist = True
|
|
||||||
envlist = pep8, py33
|
|
||||||
|
|
||||||
[testenv]
|
|
||||||
whitelist_externals = py.test
|
|
||||||
usedevelop = True
|
|
||||||
deps =
|
|
||||||
-r{toxinidir}/requirements.txt
|
|
||||||
-r{toxinidir}/test-requirements.txt
|
|
||||||
setenv = VIRTUAL_ENV={envdir}
|
|
||||||
passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
|
|
||||||
commands = pytest -vv #{posargs:./tests}
|
|
||||||
|
|
||||||
[testenv:pep8]
|
|
||||||
usedevelop = False
|
|
||||||
whitelist_externals = bash
|
|
||||||
commands =
|
|
||||||
bash -c "find {toxinidir}/* -type f -name '*.py' -print0 | xargs -0 flake8"
|
|
||||||
|
|
||||||
[testenv:venv]
|
|
||||||
commands = {posargs}
|
|
||||||
|
|
||||||
[flake8]
|
|
||||||
show-source = true
|
|
||||||
builtins = _
|
|
||||||
exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg
|
|
|
@ -1,11 +0,0 @@
|
||||||
# Kubespray on KVM Virtual Machines hypervisor preparation
|
|
||||||
|
|
||||||
A simple playbook to ensure your system has the right settings to enable Kubespray
|
|
||||||
deployment on VMs.
|
|
||||||
|
|
||||||
This playbook does not create Virtual Machines, nor does it run Kubespray itself.
|
|
||||||
|
|
||||||
## User creation
|
|
||||||
|
|
||||||
If you want to create a user for running Kubespray deployment, you should specify
|
|
||||||
both `k8s_deployment_user` and `k8s_deployment_user_pkey_path`.
|
|
|
@ -1,3 +0,0 @@
|
||||||
#k8s_deployment_user: kubespray
|
|
||||||
#k8s_deployment_user_pkey_path: /tmp/ssh_rsa
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
---
|
|
||||||
- hosts: localhost
|
|
||||||
gather_facts: False
|
|
||||||
become: yes
|
|
||||||
vars:
|
|
||||||
- bootstrap_os: none
|
|
||||||
roles:
|
|
||||||
- kvm-setup
|
|
|
@ -1,30 +0,0 @@
|
||||||
---
|
|
||||||
|
|
||||||
- name: Install required packages
|
|
||||||
package:
|
|
||||||
name: "{{ item }}"
|
|
||||||
state: present
|
|
||||||
with_items:
|
|
||||||
- bind-utils
|
|
||||||
- ntp
|
|
||||||
when: ansible_os_family == "RedHat"
|
|
||||||
|
|
||||||
- name: Install required packages
|
|
||||||
apt:
|
|
||||||
upgrade: yes
|
|
||||||
update_cache: yes
|
|
||||||
cache_valid_time: 3600
|
|
||||||
name: "{{ item }}"
|
|
||||||
state: present
|
|
||||||
install_recommends: no
|
|
||||||
with_items:
|
|
||||||
- dnsutils
|
|
||||||
- ntp
|
|
||||||
when: ansible_os_family == "Debian"
|
|
||||||
|
|
||||||
# Create deployment user if required
|
|
||||||
- include: user.yml
|
|
||||||
when: k8s_deployment_user is defined
|
|
||||||
|
|
||||||
# Set proper sysctl values
|
|
||||||
- include: sysctl.yml
|
|
|
@ -1,46 +0,0 @@
|
||||||
---
|
|
||||||
- name: Load br_netfilter module
|
|
||||||
modprobe:
|
|
||||||
name: br_netfilter
|
|
||||||
state: present
|
|
||||||
register: br_netfilter
|
|
||||||
|
|
||||||
- name: Add br_netfilter into /etc/modules
|
|
||||||
lineinfile:
|
|
||||||
dest: /etc/modules
|
|
||||||
state: present
|
|
||||||
line: 'br_netfilter'
|
|
||||||
when: br_netfilter is defined and ansible_os_family == 'Debian'
|
|
||||||
|
|
||||||
- name: Add br_netfilter into /etc/modules-load.d/kubespray.conf
|
|
||||||
copy:
|
|
||||||
dest: /etc/modules-load.d/kubespray.conf
|
|
||||||
content: |-
|
|
||||||
### This file is managed by Ansible
|
|
||||||
br-netfilter
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: 0644
|
|
||||||
when: br_netfilter is defined
|
|
||||||
|
|
||||||
|
|
||||||
- name: Enable net.ipv4.ip_forward in sysctl
|
|
||||||
sysctl:
|
|
||||||
name: net.ipv4.ip_forward
|
|
||||||
value: 1
|
|
||||||
sysctl_file: "{{ sysctl_file_path }}"
|
|
||||||
state: present
|
|
||||||
reload: yes
|
|
||||||
|
|
||||||
- name: Set bridge-nf-call-{arptables,iptables} to 0
|
|
||||||
sysctl:
|
|
||||||
name: "{{ item }}"
|
|
||||||
state: present
|
|
||||||
value: 0
|
|
||||||
sysctl_file: "{{ sysctl_file_path }}"
|
|
||||||
reload: yes
|
|
||||||
with_items:
|
|
||||||
- net.bridge.bridge-nf-call-arptables
|
|
||||||
- net.bridge.bridge-nf-call-ip6tables
|
|
||||||
- net.bridge.bridge-nf-call-iptables
|
|
||||||
when: br_netfilter is defined
|
|
|
@ -1,47 +0,0 @@
|
||||||
---
|
|
||||||
- name: Create user {{ k8s_deployment_user }}
|
|
||||||
user:
|
|
||||||
name: "{{ k8s_deployment_user }}"
|
|
||||||
groups: adm
|
|
||||||
shell: /bin/bash
|
|
||||||
|
|
||||||
- name: Ensure that .ssh exists
|
|
||||||
file:
|
|
||||||
path: "/home/{{ k8s_deployment_user }}/.ssh"
|
|
||||||
state: directory
|
|
||||||
owner: "{{ k8s_deployment_user }}"
|
|
||||||
group: "{{ k8s_deployment_user }}"
|
|
||||||
mode: 0700
|
|
||||||
|
|
||||||
- name: Configure sudo for deployment user
|
|
||||||
copy:
|
|
||||||
content: |
|
|
||||||
%{{ k8s_deployment_user }} ALL=(ALL) NOPASSWD: ALL
|
|
||||||
dest: "/etc/sudoers.d/55-k8s-deployment"
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: 0644
|
|
||||||
|
|
||||||
- name: Write private SSH key
|
|
||||||
copy:
|
|
||||||
src: "{{ k8s_deployment_user_pkey_path }}"
|
|
||||||
dest: "/home/{{ k8s_deployment_user }}/.ssh/id_rsa"
|
|
||||||
mode: 0400
|
|
||||||
owner: "{{ k8s_deployment_user }}"
|
|
||||||
group: "{{ k8s_deployment_user }}"
|
|
||||||
when: k8s_deployment_user_pkey_path is defined
|
|
||||||
|
|
||||||
- name: Write public SSH key
|
|
||||||
shell: "ssh-keygen -y -f /home/{{ k8s_deployment_user }}/.ssh/id_rsa \
|
|
||||||
> /home/{{ k8s_deployment_user }}/.ssh/authorized_keys"
|
|
||||||
args:
|
|
||||||
creates: "/home/{{ k8s_deployment_user }}/.ssh/authorized_keys"
|
|
||||||
when: k8s_deployment_user_pkey_path is defined
|
|
||||||
|
|
||||||
- name: Fix ssh-pub-key permissions
|
|
||||||
file:
|
|
||||||
path: "/home/{{ k8s_deployment_user }}/.ssh/authorized_keys"
|
|
||||||
mode: 0600
|
|
||||||
owner: "{{ k8s_deployment_user }}"
|
|
||||||
group: "{{ k8s_deployment_user }}"
|
|
||||||
when: k8s_deployment_user_pkey_path is defined
|
|
|
@ -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
|
|
|
@ -1,49 +0,0 @@
|
||||||
---
|
|
||||||
- name: Check ansible version
|
|
||||||
import_playbook: ansible_version.yml
|
|
||||||
|
|
||||||
- hosts: localhost
|
|
||||||
strategy: linear
|
|
||||||
vars:
|
|
||||||
mitogen_version: 0.3.2
|
|
||||||
mitogen_url: https://github.com/mitogen-hq/mitogen/archive/refs/tags/v{{ mitogen_version }}.tar.gz
|
|
||||||
ansible_connection: local
|
|
||||||
tasks:
|
|
||||||
- name: Create mitogen plugin dir
|
|
||||||
file:
|
|
||||||
path: "{{ item }}"
|
|
||||||
state: directory
|
|
||||||
mode: 0755
|
|
||||||
become: false
|
|
||||||
loop:
|
|
||||||
- "{{ playbook_dir }}/plugins/mitogen"
|
|
||||||
- "{{ playbook_dir }}/dist"
|
|
||||||
|
|
||||||
- name: download mitogen release
|
|
||||||
get_url:
|
|
||||||
url: "{{ mitogen_url }}"
|
|
||||||
dest: "{{ playbook_dir }}/dist/mitogen_{{ mitogen_version }}.tar.gz"
|
|
||||||
validate_certs: true
|
|
||||||
|
|
||||||
- name: extract archive
|
|
||||||
unarchive:
|
|
||||||
src: "{{ playbook_dir }}/dist/mitogen_{{ mitogen_version }}.tar.gz"
|
|
||||||
dest: "{{ playbook_dir }}/dist/"
|
|
||||||
|
|
||||||
- name: copy plugin
|
|
||||||
synchronize:
|
|
||||||
src: "{{ playbook_dir }}/dist/mitogen-{{ mitogen_version }}/"
|
|
||||||
dest: "{{ playbook_dir }}/plugins/mitogen"
|
|
||||||
|
|
||||||
- name: add strategy to ansible.cfg
|
|
||||||
ini_file:
|
|
||||||
path: ansible.cfg
|
|
||||||
mode: 0644
|
|
||||||
section: "{{ item.section | d('defaults') }}"
|
|
||||||
option: "{{ item.option }}"
|
|
||||||
value: "{{ item.value }}"
|
|
||||||
with_items:
|
|
||||||
- option: strategy
|
|
||||||
value: mitogen_linear
|
|
||||||
- option: strategy_plugins
|
|
||||||
value: plugins/mitogen/ansible_mitogen/plugins/strategy
|
|
|
@ -1,92 +0,0 @@
|
||||||
# Deploying a Kubespray Kubernetes Cluster with GlusterFS
|
|
||||||
|
|
||||||
You can either deploy using Ansible on its own by supplying your own inventory file or by using Terraform to create the VMs and then providing a dynamic inventory to Ansible. The following two sections are self-contained, you don't need to go through one to use the other. So, if you want to provision with Terraform, you can skip the **Using an Ansible inventory** section, and if you want to provision with a pre-built ansible inventory, you can neglect the **Using Terraform and Ansible** section.
|
|
||||||
|
|
||||||
## Using an Ansible inventory
|
|
||||||
|
|
||||||
In the same directory of this ReadMe file you should find a file named `inventory.example` which contains an example setup. Please note that, additionally to the Kubernetes nodes/masters, we define a set of machines for GlusterFS and we add them to the group `[gfs-cluster]`, which in turn is added to the larger `[network-storage]` group as a child group.
|
|
||||||
|
|
||||||
Change that file to reflect your local setup (adding more machines or removing them and setting the adequate ip numbers), and save it to `inventory/sample/k8s_gfs_inventory`. Make sure that the settings on `inventory/sample/group_vars/all.yml` make sense with your deployment. Then execute change to the kubespray root folder, and execute (supposing that the machines are all using ubuntu):
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ansible-playbook -b --become-user=root -i inventory/sample/k8s_gfs_inventory --user=ubuntu ./cluster.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
This will provision your Kubernetes cluster. Then, to provision and configure the GlusterFS cluster, from the same directory execute:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ansible-playbook -b --become-user=root -i inventory/sample/k8s_gfs_inventory --user=ubuntu ./contrib/network-storage/glusterfs/glusterfs.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
If your machines are not using Ubuntu, you need to change the `--user=ubuntu` to the correct user. Alternatively, if your Kubernetes machines are using one OS and your GlusterFS a different one, you can instead specify the `ansible_ssh_user=<correct-user>` variable in the inventory file that you just created, for each machine/VM:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
k8s-master-1 ansible_ssh_host=192.168.0.147 ip=192.168.0.147 ansible_ssh_user=core
|
|
||||||
k8s-master-node-1 ansible_ssh_host=192.168.0.148 ip=192.168.0.148 ansible_ssh_user=core
|
|
||||||
k8s-master-node-2 ansible_ssh_host=192.168.0.146 ip=192.168.0.146 ansible_ssh_user=core
|
|
||||||
```
|
|
||||||
|
|
||||||
## Using Terraform and Ansible
|
|
||||||
|
|
||||||
First step is to fill in a `my-kubespray-gluster-cluster.tfvars` file with the specification desired for your cluster. An example with all required variables would look like:
|
|
||||||
|
|
||||||
```ini
|
|
||||||
cluster_name = "cluster1"
|
|
||||||
number_of_k8s_masters = "1"
|
|
||||||
number_of_k8s_masters_no_floating_ip = "2"
|
|
||||||
number_of_k8s_nodes_no_floating_ip = "0"
|
|
||||||
number_of_k8s_nodes = "0"
|
|
||||||
public_key_path = "~/.ssh/my-desired-key.pub"
|
|
||||||
image = "Ubuntu 16.04"
|
|
||||||
ssh_user = "ubuntu"
|
|
||||||
flavor_k8s_node = "node-flavor-id-in-your-openstack"
|
|
||||||
flavor_k8s_master = "master-flavor-id-in-your-openstack"
|
|
||||||
network_name = "k8s-network"
|
|
||||||
floatingip_pool = "net_external"
|
|
||||||
|
|
||||||
# GlusterFS variables
|
|
||||||
flavor_gfs_node = "gluster-flavor-id-in-your-openstack"
|
|
||||||
image_gfs = "Ubuntu 16.04"
|
|
||||||
number_of_gfs_nodes_no_floating_ip = "3"
|
|
||||||
gfs_volume_size_in_gb = "50"
|
|
||||||
ssh_user_gfs = "ubuntu"
|
|
||||||
```
|
|
||||||
|
|
||||||
As explained in the general terraform/openstack guide, you need to source your OpenStack credentials file, add your ssh-key to the ssh-agent and setup environment variables for terraform:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
$ source ~/.stackrc
|
|
||||||
$ eval $(ssh-agent -s)
|
|
||||||
$ ssh-add ~/.ssh/my-desired-key
|
|
||||||
$ echo Setting up Terraform creds && \
|
|
||||||
export TF_VAR_username=${OS_USERNAME} && \
|
|
||||||
export TF_VAR_password=${OS_PASSWORD} && \
|
|
||||||
export TF_VAR_tenant=${OS_TENANT_NAME} && \
|
|
||||||
export TF_VAR_auth_url=${OS_AUTH_URL}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then, standing on the kubespray directory (root base of the Git checkout), issue the following terraform command to create the VMs for the cluster:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
terraform apply -state=contrib/terraform/openstack/terraform.tfstate -var-file=my-kubespray-gluster-cluster.tfvars contrib/terraform/openstack
|
|
||||||
```
|
|
||||||
|
|
||||||
This will create both your Kubernetes and Gluster VMs. Make sure that the ansible file `contrib/terraform/openstack/group_vars/all.yml` includes any ansible variable that you want to setup (like, for instance, the type of machine for bootstrapping).
|
|
||||||
|
|
||||||
Then, provision your Kubernetes (kubespray) cluster with the following ansible call:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ansible-playbook -b --become-user=root -i contrib/terraform/openstack/hosts ./cluster.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally, provision the glusterfs nodes and add the Persistent Volume setup for GlusterFS in Kubernetes through the following ansible call:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
ansible-playbook -b --become-user=root -i contrib/terraform/openstack/hosts ./contrib/network-storage/glusterfs/glusterfs.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
If you need to destroy the cluster, you can run:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
terraform destroy -state=contrib/terraform/openstack/terraform.tfstate -var-file=my-kubespray-gluster-cluster.tfvars contrib/terraform/openstack
|
|
||||||
```
|
|
|
@ -1,24 +0,0 @@
|
||||||
---
|
|
||||||
- hosts: gfs-cluster
|
|
||||||
gather_facts: false
|
|
||||||
vars:
|
|
||||||
ansible_ssh_pipelining: false
|
|
||||||
roles:
|
|
||||||
- { role: bootstrap-os, tags: bootstrap-os}
|
|
||||||
|
|
||||||
- hosts: all
|
|
||||||
gather_facts: true
|
|
||||||
|
|
||||||
- hosts: gfs-cluster
|
|
||||||
vars:
|
|
||||||
ansible_ssh_pipelining: true
|
|
||||||
roles:
|
|
||||||
- { role: glusterfs/server }
|
|
||||||
|
|
||||||
- hosts: k8s_cluster
|
|
||||||
roles:
|
|
||||||
- { role: glusterfs/client }
|
|
||||||
|
|
||||||
- hosts: kube_control_plane[0]
|
|
||||||
roles:
|
|
||||||
- { role: kubernetes-pv }
|
|
|
@ -1 +0,0 @@
|
||||||
../../../inventory/local/group_vars
|
|
|
@ -1,44 +0,0 @@
|
||||||
# ## Configure 'ip' variable to bind kubernetes services on a
|
|
||||||
# ## different ip than the default iface
|
|
||||||
# node1 ansible_ssh_host=95.54.0.12 # ip=10.3.0.1
|
|
||||||
# node2 ansible_ssh_host=95.54.0.13 # ip=10.3.0.2
|
|
||||||
# node3 ansible_ssh_host=95.54.0.14 # ip=10.3.0.3
|
|
||||||
# node4 ansible_ssh_host=95.54.0.15 # ip=10.3.0.4
|
|
||||||
# node5 ansible_ssh_host=95.54.0.16 # ip=10.3.0.5
|
|
||||||
# node6 ansible_ssh_host=95.54.0.17 # ip=10.3.0.6
|
|
||||||
#
|
|
||||||
# ## GlusterFS nodes
|
|
||||||
# ## Set disk_volume_device_1 to desired device for gluster brick, if different to /dev/vdb (default).
|
|
||||||
# ## As in the previous case, you can set ip to give direct communication on internal IPs
|
|
||||||
# gfs_node1 ansible_ssh_host=95.54.0.18 # disk_volume_device_1=/dev/vdc ip=10.3.0.7
|
|
||||||
# gfs_node2 ansible_ssh_host=95.54.0.19 # disk_volume_device_1=/dev/vdc ip=10.3.0.8
|
|
||||||
# gfs_node3 ansible_ssh_host=95.54.0.20 # disk_volume_device_1=/dev/vdc ip=10.3.0.9
|
|
||||||
|
|
||||||
# [kube_control_plane]
|
|
||||||
# node1
|
|
||||||
# node2
|
|
||||||
|
|
||||||
# [etcd]
|
|
||||||
# node1
|
|
||||||
# node2
|
|
||||||
# node3
|
|
||||||
|
|
||||||
# [kube_node]
|
|
||||||
# node2
|
|
||||||
# node3
|
|
||||||
# node4
|
|
||||||
# node5
|
|
||||||
# node6
|
|
||||||
|
|
||||||
# [k8s_cluster:children]
|
|
||||||
# kube_node
|
|
||||||
# kube_control_plane
|
|
||||||
|
|
||||||
# [gfs-cluster]
|
|
||||||
# gfs_node1
|
|
||||||
# gfs_node2
|
|
||||||
# gfs_node3
|
|
||||||
|
|
||||||
# [network-storage:children]
|
|
||||||
# gfs-cluster
|
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
../../../../roles/bootstrap-os
|
|
|
@ -1,50 +0,0 @@
|
||||||
# Ansible Role: GlusterFS
|
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/geerlingguy/ansible-role-glusterfs.svg?branch=master)](https://travis-ci.org/geerlingguy/ansible-role-glusterfs)
|
|
||||||
|
|
||||||
Installs and configures GlusterFS on Linux.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
For GlusterFS to connect between servers, TCP ports `24007`, `24008`, and `24009`/`49152`+ (that port, plus an additional incremented port for each additional server in the cluster; the latter if GlusterFS is version 3.4+), and TCP/UDP port `111` must be open. You can open these using whatever firewall you wish (this can easily be configured using the `geerlingguy.firewall` role).
|
|
||||||
|
|
||||||
This role performs basic installation and setup of Gluster, but it does not configure or mount bricks (volumes), since that step is easier to do in a series of plays in your own playbook. Ansible 1.9+ includes the [`gluster_volume`](https://docs.ansible.com/ansible/latest/collections/gluster/gluster/gluster_volume_module.html) module to ease the management of Gluster volumes.
|
|
||||||
|
|
||||||
## Role Variables
|
|
||||||
|
|
||||||
Available variables are listed below, along with default values (see `defaults/main.yml`):
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
glusterfs_default_release: ""
|
|
||||||
```
|
|
||||||
|
|
||||||
You can specify a `default_release` for apt on Debian/Ubuntu by overriding this variable. This is helpful if you need a different package or version for the main GlusterFS packages (e.g. GlusterFS 3.5.x instead of 3.2.x with the `wheezy-backports` default release on Debian Wheezy).
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
glusterfs_ppa_use: yes
|
|
||||||
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.
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
None.
|
|
||||||
|
|
||||||
## Example Playbook
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: server
|
|
||||||
roles:
|
|
||||||
- geerlingguy.glusterfs
|
|
||||||
```
|
|
||||||
|
|
||||||
For a real-world use example, read through [Simple GlusterFS Setup with Ansible](http://www.jeffgeerling.com/blog/simple-glusterfs-setup-ansible), a blog post by this role's author, which is included in Chapter 8 of [Ansible for DevOps](https://www.ansiblefordevops.com/).
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT / BSD
|
|
||||||
|
|
||||||
## Author Information
|
|
||||||
|
|
||||||
This role was created in 2015 by [Jeff Geerling](http://www.jeffgeerling.com/), author of [Ansible for DevOps](https://www.ansiblefordevops.com/).
|
|
|
@ -1,11 +0,0 @@
|
||||||
---
|
|
||||||
# For Ubuntu.
|
|
||||||
glusterfs_default_release: ""
|
|
||||||
glusterfs_ppa_use: yes
|
|
||||||
glusterfs_ppa_version: "4.1"
|
|
||||||
|
|
||||||
# Gluster configuration.
|
|
||||||
gluster_mount_dir: /mnt/gluster
|
|
||||||
gluster_volume_node_mount_dir: /mnt/xfs-drive-gluster
|
|
||||||
gluster_brick_dir: "{{ gluster_volume_node_mount_dir }}/brick"
|
|
||||||
gluster_brick_name: gluster
|
|
|
@ -1,30 +0,0 @@
|
||||||
---
|
|
||||||
dependencies: []
|
|
||||||
|
|
||||||
galaxy_info:
|
|
||||||
author: geerlingguy
|
|
||||||
description: GlusterFS installation for Linux.
|
|
||||||
company: "Midwestern Mac, LLC"
|
|
||||||
license: "license (BSD, MIT)"
|
|
||||||
min_ansible_version: 2.0
|
|
||||||
platforms:
|
|
||||||
- name: EL
|
|
||||||
versions:
|
|
||||||
- 6
|
|
||||||
- 7
|
|
||||||
- name: Ubuntu
|
|
||||||
versions:
|
|
||||||
- precise
|
|
||||||
- trusty
|
|
||||||
- xenial
|
|
||||||
- name: Debian
|
|
||||||
versions:
|
|
||||||
- wheezy
|
|
||||||
- jessie
|
|
||||||
galaxy_tags:
|
|
||||||
- system
|
|
||||||
- networking
|
|
||||||
- cloud
|
|
||||||
- clustering
|
|
||||||
- files
|
|
||||||
- sharing
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue