Merge branch 'master' into hostname-alias

This commit is contained in:
Matthew Mosesohn 2016-11-14 09:32:35 +03:00 committed by GitHub
commit 45c2900e71
94 changed files with 1352 additions and 597 deletions

View file

@ -10,89 +10,104 @@ env:
TEST_ID=$TRAVIS_JOB_NUMBER TEST_ID=$TRAVIS_JOB_NUMBER
CONTAINER_ENGINE=docker CONTAINER_ENGINE=docker
PRIVATE_KEY=$GCE_PRIVATE_KEY PRIVATE_KEY=$GCE_PRIVATE_KEY
GS_ACCESS_KEY_ID=$GS_KEY
GS_SECRET_ACCESS_KEY=$GS_SECRET
ANSIBLE_KEEP_REMOTE_FILES=1 ANSIBLE_KEEP_REMOTE_FILES=1
CLUSTER_MODE=default
matrix: matrix:
# Debian Jessie # Debian Jessie
- >- - >-
KUBE_NETWORK_PLUGIN=flannel KUBE_NETWORK_PLUGIN=flannel
CLOUD_IMAGE=debian-8-kubespray CLOUD_IMAGE=debian-8-kubespray
CLOUD_REGION=europe-west1-b CLOUD_REGION=europe-west1-b
CLUSTER_MODE=default
- >- - >-
KUBE_NETWORK_PLUGIN=calico KUBE_NETWORK_PLUGIN=calico
CLOUD_IMAGE=debian-8-kubespray CLOUD_IMAGE=debian-8-kubespray
CLOUD_REGION=us-central1-c CLOUD_REGION=us-central1-c
CLUSTER_MODE=default
- >- - >-
KUBE_NETWORK_PLUGIN=weave KUBE_NETWORK_PLUGIN=weave
CLOUD_IMAGE=debian-8-kubespray CLOUD_IMAGE=debian-8-kubespray
CLOUD_REGION=us-east1-d CLOUD_REGION=us-east1-d
CLUSTER_MODE=default
# Centos 7 # Centos 7
- >- - >-
KUBE_NETWORK_PLUGIN=flannel KUBE_NETWORK_PLUGIN=flannel
CLOUD_IMAGE=centos-7-sudo CLOUD_IMAGE=centos-7-sudo
CLOUD_REGION=asia-east1-c CLOUD_REGION=asia-east1-c
CLUSTER_MODE=default
- >- - >-
KUBE_NETWORK_PLUGIN=calico KUBE_NETWORK_PLUGIN=calico
CLOUD_IMAGE=centos-7-sudo CLOUD_IMAGE=centos-7-sudo
CLOUD_REGION=europe-west1-b CLOUD_REGION=europe-west1-b
CLUSTER_MODE=default
- >- - >-
KUBE_NETWORK_PLUGIN=weave KUBE_NETWORK_PLUGIN=weave
CLOUD_IMAGE=centos-7-sudo CLOUD_IMAGE=centos-7-sudo
CLOUD_REGION=us-central1-c CLOUD_REGION=us-central1-c
CLUSTER_MODE=default
# Redhat 7 # Redhat 7
- >- - >-
KUBE_NETWORK_PLUGIN=flannel KUBE_NETWORK_PLUGIN=flannel
CLOUD_IMAGE=rhel-7-sudo CLOUD_IMAGE=rhel-7-sudo
CLOUD_REGION=us-east1-d CLOUD_REGION=us-east1-d
CLUSTER_MODE=default
- >- - >-
KUBE_NETWORK_PLUGIN=calico KUBE_NETWORK_PLUGIN=calico
CLOUD_IMAGE=rhel-7-sudo CLOUD_IMAGE=rhel-7-sudo
CLOUD_REGION=asia-east1-c CLOUD_REGION=asia-east1-c
CLUSTER_MODE=default
- >- - >-
KUBE_NETWORK_PLUGIN=weave KUBE_NETWORK_PLUGIN=weave
CLOUD_IMAGE=rhel-7-sudo CLOUD_IMAGE=rhel-7-sudo
CLOUD_REGION=europe-west1-b CLOUD_REGION=europe-west1-b
CLUSTER_MODE=default
# Ubuntu 16.04 # Ubuntu 16.04
- >- - >-
KUBE_NETWORK_PLUGIN=flannel KUBE_NETWORK_PLUGIN=flannel
CLOUD_IMAGE=ubuntu-1604-xenial CLOUD_IMAGE=ubuntu-1604-xenial
CLOUD_REGION=us-central1-c CLOUD_REGION=us-central1-c
CLUSTER_MODE=default
- >- - >-
KUBE_NETWORK_PLUGIN=calico KUBE_NETWORK_PLUGIN=calico
CLOUD_IMAGE=ubuntu-1604-xenial CLOUD_IMAGE=ubuntu-1604-xenial
CLOUD_REGION=us-east1-d CLOUD_REGION=us-east1-d
CLUSTER_MODE=default
- >- - >-
KUBE_NETWORK_PLUGIN=weave KUBE_NETWORK_PLUGIN=weave
CLOUD_IMAGE=ubuntu-1604-xenial CLOUD_IMAGE=ubuntu-1604-xenial
CLOUD_REGION=asia-east1-c CLOUD_REGION=asia-east1-c
CLUSTER_MODE=default
# Ubuntu 15.10 # Extra cases for separated roles
- >- - >-
KUBE_NETWORK_PLUGIN=flannel KUBE_NETWORK_PLUGIN=flannel
CLOUD_IMAGE=ubuntu-1510-wily CLOUD_IMAGE=rhel-7-sudo
CLOUD_REGION=europe-west1-b CLOUD_REGION=europe-west1-b
CLUSTER_MODE=separate
- >- - >-
KUBE_NETWORK_PLUGIN=calico KUBE_NETWORK_PLUGIN=calico
CLOUD_IMAGE=ubuntu-1510-wily CLOUD_IMAGE=ubuntu-1604-xenial
CLOUD_REGION=us-central1-a CLOUD_REGION=us-central1-a
CLUSTER_MODE=separate
- >- - >-
KUBE_NETWORK_PLUGIN=weave KUBE_NETWORK_PLUGIN=weave
CLOUD_IMAGE=ubuntu-1510-wily CLOUD_IMAGE=debian-8-kubespray
CLOUD_REGION=us-east1-d CLOUD_REGION=us-east1-d
CLUSTER_MODE=separate
before_install: before_install:
# Install Ansible. # Install Ansible.
- pip install --user boto -U
- pip install --user ansible - pip install --user ansible
- pip install --user netaddr - pip install --user netaddr
- pip install --user apache-libcloud # W/A https://github.com/ansible/ansible-modules-core/issues/5196#issuecomment-253766186
- pip install --user apache-libcloud==0.20.1
- pip install --user boto==2.9.0 -U
cache: cache:
- directories: - directories:
@ -109,12 +124,11 @@ before_script:
- $HOME/.local/bin/ansible-playbook --version - $HOME/.local/bin/ansible-playbook --version
- cp tests/ansible.cfg . - 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" # - "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"
## Configure ansible deployment logs to be collected as an artifact. Enable when GCS configured, see https://docs.travis-ci.com/user/deployment/gcs
# - $HOME/.local/bin/ansible-playbook -u $SSH_USER -e ansible_ssh_user=$SSH_USER $SSH_ARGS -b --become-user=root scritps/configure-logs.yaml
script: script:
- > - >
$HOME/.local/bin/ansible-playbook tests/cloud_playbooks/create-gce.yml -i tests/local_inventory/hosts -c local $LOG_LEVEL $HOME/.local/bin/ansible-playbook tests/cloud_playbooks/create-gce.yml -i tests/local_inventory/hosts.cfg -c local $LOG_LEVEL
-e mode=${CLUSTER_MODE}
-e test_id=${TEST_ID} -e test_id=${TEST_ID}
-e kube_network_plugin=${KUBE_NETWORK_PLUGIN} -e kube_network_plugin=${KUBE_NETWORK_PLUGIN}
-e gce_project_id=${GCE_PROJECT_ID} -e gce_project_id=${GCE_PROJECT_ID}
@ -133,8 +147,21 @@ script:
- $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 - $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 ## 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 - $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
## Collect env info, enable it once GCS configured, see https://docs.travis-ci.com/user/deployment/gcs
# - $HOME/.local/bin/ansible-playbook -i inventory/inventory.ini -u $SSH_USER -e ansible_ssh_user=$SSH_USER $SSH_ARGS -b --become-user=root scritps/collect-info.yaml after_failure:
- >
$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 dir=$HOME
scripts/collect-info.yaml
- >
$HOME/.local/bin/ansible-playbook tests/cloud_playbooks/upload-logs-gcs.yml -i "localhost," -c local
-e kube_network_plugin=${KUBE_NETWORK_PLUGIN}
-e gce_project_id=${GCE_PROJECT_ID}
-e gs_key=${GS_ACCESS_KEY_ID}
-e gs_skey=${GS_SECRET_ACCESS_KEY}
-e ostype=${CLOUD_IMAGE}
-e commit=${TRAVIS_COMMIT}
-e dir=${HOME}
after_script: after_script:
- > - >

3
OWNERS
View file

@ -4,3 +4,6 @@
owners: owners:
- Smana - Smana
- ant31 - ant31
- bogdando
- mattymo
- rsmitty

View file

@ -41,7 +41,7 @@ Supported Linux distributions
Versions Versions
-------------- --------------
[kubernetes](https://github.com/kubernetes/kubernetes/releases) v1.4.0 <br> [kubernetes](https://github.com/kubernetes/kubernetes/releases) v1.4.3 <br>
[etcd](https://github.com/coreos/etcd/releases) v3.0.1 <br> [etcd](https://github.com/coreos/etcd/releases) v3.0.1 <br>
[flanneld](https://github.com/coreos/flannel/releases) v0.6.2 <br> [flanneld](https://github.com/coreos/flannel/releases) v0.6.2 <br>
[calicoctl](https://github.com/projectcalico/calico-docker/releases) v0.22.0 <br> [calicoctl](https://github.com/projectcalico/calico-docker/releases) v0.22.0 <br>

15
Vagrantfile vendored
View file

@ -16,7 +16,7 @@ $vm_cpus = 1
$shared_folders = {} $shared_folders = {}
$forwarded_ports = {} $forwarded_ports = {}
$subnet = "172.17.8" $subnet = "172.17.8"
$box = "bento/ubuntu-14.04" $box = "bento/ubuntu-16.04"
host_vars = {} host_vars = {}
@ -38,6 +38,13 @@ if ! File.exist?(File.join(File.dirname($inventory), "hosts"))
end end
end 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| Vagrant.configure("2") do |config|
# always use Vagrants insecure key # always use Vagrants insecure key
config.ssh.insert_key = false config.ssh.insert_key = false
@ -52,6 +59,12 @@ Vagrant.configure("2") do |config|
config.vm.define vm_name = "%s-%02d" % [$instance_name_prefix, i] do |config| config.vm.define vm_name = "%s-%02d" % [$instance_name_prefix, i] do |config|
config.vm.hostname = vm_name config.vm.hostname = vm_name
if Vagrant.has_plugin?("vagrant-proxyconf")
config.proxy.http = ENV['HTTP_PROXY'] || ENV['http_proxy'] || ""
config.proxy.https = ENV['HTTPS_PROXY'] || ENV['https_proxy'] || ""
config.proxy.no_proxy = $no_proxy
end
if $expose_docker_tcp if $expose_docker_tcp
config.vm.network "forwarded_port", guest: 2375, host: ($expose_docker_tcp + i - 1), auto_correct: true config.vm.network "forwarded_port", guest: 2375, host: ($expose_docker_tcp + i - 1), auto_correct: true
end end

View file

@ -2,3 +2,6 @@
pipelining=True pipelining=True
[defaults] [defaults]
host_key_checking=False host_key_checking=False
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp

View file

@ -10,22 +10,25 @@
- hosts: all - hosts: all
gather_facts: true gather_facts: true
- hosts: etcd:!k8s-cluster - hosts: all
roles: roles:
- { role: kubernetes/preinstall, tags: preinstall } - { role: kubernetes/preinstall, tags: preinstall }
- hosts: etcd:!k8s-cluster
roles:
- { role: etcd, tags: etcd } - { role: etcd, tags: etcd }
- hosts: k8s-cluster - hosts: k8s-cluster
roles: roles:
- { role: kubernetes/preinstall, tags: preinstall }
- { role: etcd, tags: etcd } - { role: etcd, tags: etcd }
- { role: kubernetes/node, tags: node } - { role: kubernetes/node, tags: node }
- { role: network_plugin, tags: network } - { role: network_plugin, tags: network }
- hosts: kube-master - hosts: kube-master
roles: roles:
- { role: kubernetes/preinstall, tags: preinstall }
- { role: kubernetes/master, tags: master } - { role: kubernetes/master, tags: master }
- { role: kubernetes-apps/lib, tags: apps }
- { role: kubernetes-apps/network_plugin, tags: network }
- hosts: k8s-cluster - hosts: k8s-cluster
roles: roles:
@ -33,4 +36,5 @@
- hosts: kube-master[0] - hosts: kube-master[0]
roles: roles:
- { role: kubernetes-apps/lib, tags: apps }
- { role: kubernetes-apps, tags: apps } - { role: kubernetes-apps, tags: apps }

View file

@ -5,14 +5,13 @@ Openstack.
## Status ## Status
This will install a Kubernetes cluster on an Openstack Cloud. It is tested on a This will install a Kubernetes cluster on an Openstack Cloud. It has been tested on a
OpenStack Cloud provided by [BlueBox](https://www.blueboxcloud.com/) and OpenStack Cloud provided by [BlueBox](https://www.blueboxcloud.com/) and on OpenStack at [EMBL-EBI's](http://www.ebi.ac.uk/) [EMBASSY Cloud](http://www.embassycloud.org/). This should work on most modern installs of OpenStack that support the basic
should work on most modern installs of OpenStack that support the basic
services. services.
There are some assumptions made to try and ensure it will work on your openstack cluster. There are some assumptions made to try and ensure it will work on your openstack cluster.
* floating-ips are used for access * floating-ips are used for access, but you can have masters and nodes that don't use floating-ips if needed. You need currently at least 1 floating ip, which we would suggest is used on a master.
* you already have a suitable OS image in glance * you already have a suitable OS image in glance
* you already have both an internal network and a floating-ip pool created * you already have both an internal network and a floating-ip pool created
* you have security-groups enabled * you have security-groups enabled
@ -24,16 +23,14 @@ There are some assumptions made to try and ensure it will work on your openstack
## Terraform ## Terraform
Terraform will be used to provision all of the OpenStack resources required to Terraform will be used to provision all of the OpenStack resources. It is also used to deploy and provision the software
run Docker Swarm. It is also used to deploy and provision the software
requirements. requirements.
### Prep ### Prep
#### OpenStack #### OpenStack
Ensure your OpenStack credentials are loaded in environment variables. This is Ensure your OpenStack credentials are loaded in environment variables. This can be done by downloading a credentials .rc file from your OpenStack dashboard and sourcing it:
how I do it:
``` ```
$ source ~/.stackrc $ source ~/.stackrc
@ -46,7 +43,7 @@ differences between OpenStack installs the Terraform does not attempt to create
these for you. these for you.
By default Terraform will expect that your networks are called `internal` and By default Terraform will expect that your networks are called `internal` and
`external`. You can change this by altering the Terraform variables `network_name` and `floatingip_pool`. `external`. You can change this by altering the Terraform variables `network_name` and `floatingip_pool`. This can be done on a new variables file or through environment variables.
A full list of variables you can change can be found at [variables.tf](variables.tf). A full list of variables you can change can be found at [variables.tf](variables.tf).
@ -76,8 +73,21 @@ $ echo Setting up Terraform creds && \
export TF_VAR_auth_url=${OS_AUTH_URL} export TF_VAR_auth_url=${OS_AUTH_URL}
``` ```
If you want to provision master or node VMs that don't use floating ips, write on a `my-terraform-vars.tfvars` file, for example:
```
number_of_k8s_masters = "1"
number_of_k8s_masters_no_floating_ip = "2"
number_of_k8s_nodes_no_floating_ip = "1"
number_of_k8s_nodes = "0"
```
This will provision one VM as master using a floating ip, two additional masters using no floating ips (these will only have private ips inside your tenancy) and one VM as node, again without a floating ip.
# Provision a Kubernetes Cluster on OpenStack # Provision a Kubernetes Cluster on OpenStack
If not using a tfvars file for your setup, then execute:
``` ```
terraform apply -state=contrib/terraform/openstack/terraform.tfstate contrib/terraform/openstack terraform apply -state=contrib/terraform/openstack/terraform.tfstate contrib/terraform/openstack
openstack_compute_secgroup_v2.k8s_master: Creating... openstack_compute_secgroup_v2.k8s_master: Creating...
@ -96,6 +106,13 @@ use the `terraform show` command.
State path: contrib/terraform/openstack/terraform.tfstate State path: contrib/terraform/openstack/terraform.tfstate
``` ```
Alternatively, if you wrote your terraform variables on a file `my-terraform-vars.tfvars`, your command would look like:
```
terraform apply -state=contrib/terraform/openstack/terraform.tfstate -var-file=my-terraform-vars.tfvars contrib/terraform/openstack
```
if you choose to add masters or nodes without floating ips (only internal ips on your OpenStack tenancy), this script will create as well a file `contrib/terraform/openstack/k8s-cluster.yml` with an ssh command for ansible to be able to access your machines tunneling through the first floating ip used. If you want to manually handling the ssh tunneling to these machines, please delete or move that file. If you want to use this, just leave it there, as ansible will pick it up automatically.
Make sure you can connect to the hosts: Make sure you can connect to the hosts:
``` ```
@ -114,6 +131,8 @@ example-k8s-master-1 | SUCCESS => {
} }
``` ```
if you are deploying a system that needs bootstrapping, like CoreOS, these might have a state `FAILED` due to CoreOS not having python. As long as the state is not `UNREACHABLE`, this is fine.
if it fails try to connect manually via SSH ... it could be somthing as simple as a stale host key. if it fails try to connect manually via SSH ... it could be somthing as simple as a stale host key.
Deploy kubernetes: Deploy kubernetes:

View file

@ -0,0 +1 @@
ansible_ssh_common_args: '-o ProxyCommand="ssh -o StrictHostKeyChecking=no -W %h:%p -q USER@BASTION_ADDRESS"'

View file

@ -1,9 +1,14 @@
# Valid bootstrap options (required): xenial, coreos, none
bootstrap_os: "none"
# Directory where the binaries will be installed # Directory where the binaries will be installed
bin_dir: /usr/local/bin bin_dir: /usr/local/bin
# Where the binaries will be downloaded. # Where the binaries will be downloaded.
# Note: ensure that you've enough disk space (about 1G) # Note: ensure that you've enough disk space (about 1G)
local_release_dir: "/tmp/releases" local_release_dir: "/tmp/releases"
# Random shifts for retrying failed ops like pushing/downloading
retry_stagger: 5
# Uncomment this line for CoreOS only. # Uncomment this line for CoreOS only.
# Directory where python binary is installed # Directory where python binary is installed
@ -28,6 +33,8 @@ kube_users:
# Kubernetes cluster name, also will be used as DNS domain # Kubernetes cluster name, also will be used as DNS domain
cluster_name: cluster.local cluster_name: cluster.local
# Subdomains of DNS domain to be resolved via /etc/resolv.conf
ndots: 5
# For some environments, each node has a pubilcally accessible # For some environments, each node has a pubilcally accessible
# address and an address it should bind services to. These are # address and an address it should bind services to. These are
@ -51,6 +58,16 @@ cluster_name: cluster.local
# but don't know about that address themselves. # but don't know about that address themselves.
# access_ip: 1.1.1.1 # access_ip: 1.1.1.1
# Etcd access modes:
# Enable multiaccess to configure clients to access all of the etcd members directly
# as the "http://hostX:port, http://hostY:port, ..." and ignore the proxy loadbalancers.
# This may be the case if clients support and loadbalance multiple etcd servers natively.
etcd_multiaccess: false
# Assume there are no internal loadbalancers for apiservers exist and listen on
# kube_apiserver_port (default 443)
loadbalancer_apiserver_localhost: true
# Choose network plugin (calico, weave or flannel) # Choose network plugin (calico, weave or flannel)
kube_network_plugin: flannel kube_network_plugin: flannel
@ -89,10 +106,12 @@ kube_apiserver_insecure_port: 8080 # (http)
# You still must manually configure all your containers to use this DNS server, # You still must manually configure all your containers to use this DNS server,
# Kubernetes won't do this for you (yet). # Kubernetes won't do this for you (yet).
# Do not install additional dnsmasq
skip_dnsmasq: false
# Upstream dns servers used by dnsmasq # Upstream dns servers used by dnsmasq
upstream_dns_servers: #upstream_dns_servers:
- 8.8.8.8 # - 8.8.8.8
- 8.8.4.4 # - 8.8.4.4
# #
# # Use dns server : https://github.com/ansibl8s/k8s-skydns/blob/master/skydns-README.md # # Use dns server : https://github.com/ansibl8s/k8s-skydns/blob/master/skydns-README.md
dns_setup: true dns_setup: true
@ -109,21 +128,6 @@ dns_server: "{{ kube_service_addresses|ipaddr('net')|ipaddr(2)|ipaddr('address')
# like you would do when using nova-client before starting the playbook. # like you would do when using nova-client before starting the playbook.
# cloud_provider: # cloud_provider:
# For multi masters architecture:
# kube-proxy doesn't support multiple apiservers for the time being so you'll need to configure your own loadbalancer
# This domain name will be inserted into the /etc/hosts file of all servers
# configuration example with haproxy :
# listen kubernetes-apiserver-https
# bind 10.99.0.21:8383
# option ssl-hello-chk
# mode tcp
# timeout client 3h
# timeout server 3h
# server master1 10.99.0.26:443
# server master2 10.99.0.27:443
# balance roundrobin
# apiserver_loadbalancer_domain_name: "lb-apiserver.kubernetes.local"
## Set these proxy values in order to update docker daemon to use proxies ## Set these proxy values in order to update docker daemon to use proxies
# http_proxy: "" # http_proxy: ""
# https_proxy: "" # https_proxy: ""
@ -134,3 +138,7 @@ dns_server: "{{ kube_service_addresses|ipaddr('net')|ipaddr(2)|ipaddr('address')
## An obvious use case is allowing insecure-registry access ## An obvious use case is allowing insecure-registry access
## to self hosted registries like so: ## to self hosted registries like so:
docker_options: "--insecure-registry={{ kube_service_addresses }}" docker_options: "--insecure-registry={{ kube_service_addresses }}"
# default packages to install within the cluster
kpm_packages: []
# - name: kube-system/grafana

View file

@ -70,6 +70,28 @@ resource "openstack_compute_instance_v2" "k8s_master" {
ssh_user = "${var.ssh_user}" ssh_user = "${var.ssh_user}"
kubespray_groups = "etcd,kube-master,kube-node,k8s-cluster" kubespray_groups = "etcd,kube-master,kube-node,k8s-cluster"
} }
}
resource "openstack_compute_instance_v2" "k8s_master_no_floating_ip" {
name = "${var.cluster_name}-k8s-master-nf-${count.index+1}"
count = "${var.number_of_k8s_masters_no_floating_ip}"
image_name = "${var.image}"
flavor_id = "${var.flavor_k8s_master}"
key_pair = "${openstack_compute_keypair_v2.k8s.name}"
network {
name = "${var.network_name}"
}
security_groups = [ "${openstack_compute_secgroup_v2.k8s_master.name}",
"${openstack_compute_secgroup_v2.k8s.name}" ]
metadata = {
ssh_user = "${var.ssh_user}"
kubespray_groups = "etcd,kube-master,kube-node,k8s-cluster"
}
provisioner "local-exec" {
command = "sed s/USER/${var.ssh_user}/ contrib/terraform/openstack/ansible_bastion_template.txt | sed s/BASTION_ADDRESS/${element(openstack_networking_floatingip_v2.k8s_master.*.address, 0)}/ > contrib/terraform/openstack/group_vars/k8s-cluster.yml"
}
} }
resource "openstack_compute_instance_v2" "k8s_node" { resource "openstack_compute_instance_v2" "k8s_node" {
@ -89,6 +111,28 @@ resource "openstack_compute_instance_v2" "k8s_node" {
} }
} }
resource "openstack_compute_instance_v2" "k8s_node_no_floating_ip" {
name = "${var.cluster_name}-k8s-node-nf-${count.index+1}"
count = "${var.number_of_k8s_nodes_no_floating_ip}"
image_name = "${var.image}"
flavor_id = "${var.flavor_k8s_node}"
key_pair = "${openstack_compute_keypair_v2.k8s.name}"
network {
name = "${var.network_name}"
}
security_groups = ["${openstack_compute_secgroup_v2.k8s.name}" ]
metadata = {
ssh_user = "${var.ssh_user}"
kubespray_groups = "kube-node,k8s-cluster"
}
provisioner "local-exec" {
command = "sed s/USER/${var.ssh_user}/ contrib/terraform/openstack/ansible_bastion_template.txt | sed s/BASTION_ADDRESS/${element(openstack_networking_floatingip_v2.k8s_master.*.address, 0)}/ > contrib/terraform/openstack/group_vars/k8s-cluster.yml"
}
}
#output "msg" { #output "msg" {
# value = "Your hosts are ready to go!\nYour ssh hosts are: ${join(", ", openstack_networking_floatingip_v2.k8s_master.*.address )}" # value = "Your hosts are ready to go!\nYour ssh hosts are: ${join(", ", openstack_networking_floatingip_v2.k8s_master.*.address )}"
#} #}

View file

@ -6,10 +6,18 @@ variable "number_of_k8s_masters" {
default = 2 default = 2
} }
variable "number_of_k8s_masters_no_floating_ip" {
default = 2
}
variable "number_of_k8s_nodes" { variable "number_of_k8s_nodes" {
default = 1 default = 1
} }
variable "number_of_k8s_nodes_no_floating_ip" {
default = 1
}
variable "public_key_path" { variable "public_key_path" {
description = "The path of the ssh pub key" description = "The path of the ssh pub key"
default = "~/.ssh/id_rsa.pub" default = "~/.ssh/id_rsa.pub"

View file

@ -10,18 +10,42 @@ docker ps | grep calico
The **calicoctl** command allows to check the status of the network workloads. The **calicoctl** command allows to check the status of the network workloads.
* Check the status of Calico nodes * Check the status of Calico nodes
```
calicoctl node status
```
or for versions prior *v1.0.0*:
``` ```
calicoctl status calicoctl status
``` ```
* Show the configured network subnet for containers * Show the configured network subnet for containers
```
calicoctl get ippool -o wide
```
or for versions prior *v1.0.0*:
``` ```
calicoctl pool show calicoctl pool show
``` ```
* Show the workloads (ip addresses of containers and their located) * Show the workloads (ip addresses of containers and their located)
```
calicoctl get workloadEndpoint -o wide
```
and
```
calicoctl get hostEndpoint -o wide
```
or for versions prior *v1.0.0*:
``` ```
calicoctl endpoint show --detail calicoctl endpoint show --detail
``` ```

View file

@ -5,10 +5,6 @@ The following components require a highly available endpoints:
* etcd cluster, * etcd cluster,
* kube-apiserver service instances. * kube-apiserver service instances.
The former provides the
[etcd-proxy](https://coreos.com/etcd/docs/latest/proxy.html) service to access
the cluster members in HA fashion.
The latter relies on a 3rd side reverse proxies, like Nginx or HAProxy, to The latter relies on a 3rd side reverse proxies, like Nginx or HAProxy, to
achieve the same goal. achieve the same goal.
@ -57,7 +53,7 @@ type. The following diagram shows how traffic to the apiserver is directed.
A user may opt to use an external loadbalancer (LB) instead. An external LB A user may opt to use an external loadbalancer (LB) instead. An external LB
provides access for external clients, while the internal LB accepts client provides access for external clients, while the internal LB accepts client
connections only to the localhost, similarly to the etcd-proxy HA endpoints. connections only to the localhost.
Given a frontend `VIP` address and `IP1, IP2` addresses of backends, here is Given a frontend `VIP` address and `IP1, IP2` addresses of backends, here is
an example configuration for a HAProxy service acting as an external LB: an example configuration for a HAProxy service acting as an external LB:
``` ```

View file

@ -1,6 +1,10 @@
Kargo's roadmap Kargo's roadmap
================= =================
### Kubeadm
- Propose kubeadm as an option in order to setup the kubernetes cluster.
That would probably improve deployment speed and certs management [#553](https://github.com/kubespray/kargo/issues/553)
### Self deployment (pull-mode) [#320](https://github.com/kubespray/kargo/issues/320) ### Self deployment (pull-mode) [#320](https://github.com/kubespray/kargo/issues/320)
- the playbook would install and configure docker/rkt and the etcd cluster - the playbook would install and configure docker/rkt and the etcd cluster
- the following data would be inserted into etcd: certs,tokens,users,inventory,group_vars. - the following data would be inserted into etcd: certs,tokens,users,inventory,group_vars.
@ -33,6 +37,7 @@ Kargo's roadmap
- test scale up cluster: +1 etcd, +1 master, +1 node - test scale up cluster: +1 etcd, +1 master, +1 node
### Lifecycle ### Lifecycle
- Adopt the kubeadm tool by delegating CM tasks it is capable to accomplish well [#553](https://github.com/kubespray/kargo/issues/553)
- Drain worker node when upgrading k8s components in a worker node. [#154](https://github.com/kubespray/kargo/issues/154) - Drain worker node when upgrading k8s components in a worker node. [#154](https://github.com/kubespray/kargo/issues/154)
- Drain worker node when shutting down/deleting an instance - Drain worker node when shutting down/deleting an instance

View file

@ -62,7 +62,7 @@ ndots: 5
# Enable multiaccess to configure clients to access all of the etcd members directly # Enable multiaccess to configure clients to access all of the etcd members directly
# as the "http://hostX:port, http://hostY:port, ..." and ignore the proxy loadbalancers. # as the "http://hostX:port, http://hostY:port, ..." and ignore the proxy loadbalancers.
# This may be the case if clients support and loadbalance multiple etcd servers natively. # This may be the case if clients support and loadbalance multiple etcd servers natively.
etcd_multiaccess: false etcd_multiaccess: true
# Assume there are no internal loadbalancers for apiservers exist and listen on # Assume there are no internal loadbalancers for apiservers exist and listen on
# kube_apiserver_port (default 443) # kube_apiserver_port (default 443)

View file

@ -10,3 +10,16 @@
# Max of 2 is allowed here (a 1 is reserved for the dns_server) # Max of 2 is allowed here (a 1 is reserved for the dns_server)
#nameservers: #nameservers:
# - 127.0.0.1 # - 127.0.0.1
# Versions
dnsmasq_version: 2.72
# Images
dnsmasq_image_repo: "andyshinn/dnsmasq"
dnsmasq_image_tag: "{{ dnsmasq_version }}"
# Skip dnsmasq setup
skip_dnsmasq: false
# Skip setting up dnsmasq daemonset
skip_dnsmasq_k8s: "{{ skip_dnsmasq }}"

View file

@ -1,5 +1,5 @@
--- ---
- include: dnsmasq.yml - include: dnsmasq.yml
when: "{{ not skip_dnsmasq|bool }}" when: "{{ not skip_dnsmasq_k8s|bool }}"
- include: resolvconf.yml - include: resolvconf.yml

View file

@ -13,7 +13,7 @@ server=/{{ dns_domain }}/{{ skydns_server }}
{% for srv in upstream_dns_servers %} {% for srv in upstream_dns_servers %}
server={{ srv }} server={{ srv }}
{% endfor %} {% endfor %}
{% elif cloud_provider == "gce" %} {% elif cloud_provider is defined and cloud_provider == "gce" %}
server=169.254.169.254 server=169.254.169.254
{% else %} {% else %}
server=8.8.8.8 server=8.8.8.8

View file

@ -14,7 +14,7 @@ spec:
spec: spec:
containers: containers:
- name: dnsmasq - name: dnsmasq
image: andyshinn/dnsmasq:2.72 image: "{{ dnsmasq_image_repo }}:{{ dnsmasq_image_tag }}"
command: command:
- dnsmasq - dnsmasq
args: args:

View file

@ -3,6 +3,7 @@
command: /bin/true command: /bin/true
notify: notify:
- Docker | reload systemd - Docker | reload systemd
- Docker | reload docker.socket
- Docker | reload docker - Docker | reload docker
- Docker | pause while Docker restarts - Docker | pause while Docker restarts
- Docker | wait for docker - Docker | wait for docker
@ -16,6 +17,12 @@
name: docker name: docker
state: restarted state: restarted
- name: Docker | reload docker.socket
service:
name: docker.socket
state: restarted
when: ansible_os_family == 'CoreOS'
- name: Docker | pause while Docker restarts - name: Docker | pause while Docker restarts
pause: seconds=10 prompt="Waiting for docker restart" pause: seconds=10 prompt="Waiting for docker restart"

View file

@ -5,16 +5,17 @@ local_release_dir: /tmp
download_run_once: False download_run_once: False
# Versions # Versions
kube_version: v1.4.0 kube_version: v1.4.3
etcd_version: v3.0.6 etcd_version: v3.0.6
#TODO(mattymo): Move calico versions to roles/network_plugins/calico/defaults #TODO(mattymo): Move calico versions to roles/network_plugins/calico/defaults
# after migration to container download # after migration to container download
calico_version: v0.22.0 calico_version: v1.0.0-beta
calico_cni_version: v1.4.2 calico_cni_version: v1.4.2
weave_version: v1.6.1 weave_version: v1.6.1
flannel_version: v0.6.2 flannel_version: v0.6.2
flannel_server_helper_version: 0.1 flannel_server_helper_version: 0.1
pod_infra_version: 3.0
# Download URL's # Download URL's
etcd_download_url: "https://storage.googleapis.com/kargo/{{etcd_version}}_etcd" etcd_download_url: "https://storage.googleapis.com/kargo/{{etcd_version}}_etcd"
@ -38,11 +39,17 @@ flannel_server_helper_image_tag: "{{ flannel_server_helper_version }}"
flannel_image_repo: "quay.io/coreos/flannel" flannel_image_repo: "quay.io/coreos/flannel"
flannel_image_tag: "{{ flannel_version }}" flannel_image_tag: "{{ flannel_version }}"
calicoctl_image_repo: "calico/ctl" calicoctl_image_repo: "calico/ctl"
calicoctl_image_tag: "{{ calico_version }}" # TODO(apanchenko): v1.0.0-beta can't execute `node run` from Docker container
# for details see https://github.com/projectcalico/calico-containers/issues/1291
calicoctl_image_tag: "v0.22.0"
calico_node_image_repo: "calico/node" calico_node_image_repo: "calico/node"
calico_node_image_tag: "{{ calico_version }}" calico_node_image_tag: "{{ calico_version }}"
calico_cni_image_repo: "calico/cni"
calico_cni_image_tag: "{{ calico_cni_version }}"
hyperkube_image_repo: "quay.io/coreos/hyperkube" hyperkube_image_repo: "quay.io/coreos/hyperkube"
hyperkube_image_tag: "{{ kube_version }}_coreos.0" hyperkube_image_tag: "{{ kube_version }}_coreos.0"
pod_infra_image_repo: "gcr.io/google_containers/pause-amd64"
pod_infra_image_tag: "{{ pod_infra_version }}"
downloads: downloads:
calico_cni_plugin: calico_cni_plugin:
@ -53,7 +60,7 @@ downloads:
url: "{{ calico_cni_download_url }}" url: "{{ calico_cni_download_url }}"
owner: "root" owner: "root"
mode: "0755" mode: "0755"
enabled: "{{ kube_network_plugin == 'calico' }}" enabled: "{{ kube_network_plugin == 'calico' or kube_network_plugin == 'canal' }}"
calico_cni_plugin_ipam: calico_cni_plugin_ipam:
dest: calico/bin/calico-ipam dest: calico/bin/calico-ipam
version: "{{calico_cni_version}}" version: "{{calico_cni_version}}"
@ -92,22 +99,31 @@ downloads:
container: true container: true
repo: "{{ flannel_image_repo }}" repo: "{{ flannel_image_repo }}"
tag: "{{ flannel_image_tag }}" tag: "{{ flannel_image_tag }}"
enabled: "{{ kube_network_plugin == 'flannel' }}" enabled: "{{ kube_network_plugin == 'flannel' or kube_network_plugin == 'canal' }}"
flannel_server_helper: flannel_server_helper:
container: true container: true
repo: "{{ flannel_server_helper_image_repo }}" repo: "{{ flannel_server_helper_image_repo }}"
tag: "{{ flannel_server_helper_image_tag }}" tag: "{{ flannel_server_helper_image_tag }}"
enabled: "{{ kube_network_plugin == 'flannel' }}" enabled: "{{ kube_network_plugin == 'flannel' or kube_network_plugin == 'canal' }}"
calicoctl: calicoctl:
container: true container: true
repo: "{{ calicoctl_image_repo }}" repo: "{{ calicoctl_image_repo }}"
tag: "{{ calicoctl_image_tag }}" tag: "{{ calicoctl_image_tag }}"
enabled: "{{ kube_network_plugin == 'calico' }}" enabled: "{{ kube_network_plugin == 'calico' or kube_network_plugin == 'canal' }}"
calico_node: calico_node:
container: true container: true
repo: "{{ calico_node_image_repo }}" repo: "{{ calico_node_image_repo }}"
tag: "{{ calico_node_image_tag }}" tag: "{{ calico_node_image_tag }}"
enabled: "{{ kube_network_plugin == 'calico' }}" enabled: "{{ kube_network_plugin == 'calico' or kube_network_plugin == 'canal' }}"
calico_cni:
container: true
repo: "{{ calico_cni_image_repo }}"
tag: "{{ calico_cni_image_tag }}"
enabled: "{{ kube_network_plugin == 'canal' }}"
pod_infra:
container: true
repo: "{{ pod_infra_image_repo }}"
tag: "{{ pod_infra_image_tag }}"
download: download:
container: "{{ file.container|default('false') }}" container: "{{ file.container|default('false') }}"

View file

@ -61,11 +61,22 @@
- set_fact: - set_fact:
fname: "{{local_release_dir}}/containers/{{download.repo|regex_replace('/|\0|:', '_')}}:{{download.tag|regex_replace('/|\0|:', '_')}}.tar" fname: "{{local_release_dir}}/containers/{{download.repo|regex_replace('/|\0|:', '_')}}:{{download.tag|regex_replace('/|\0|:', '_')}}.tar"
- name: "Set default value for 'container_changed' to false"
set_fact:
container_changed: false
- name: "Update the 'container_changed' fact"
set_fact:
container_changed: "{{ not 'up to date' in pull_task_result.stdout }}"
when: "{{ download.enabled|bool and download.container|bool }}"
delegate_to: "{{ groups['kube-master'][0] if download_run_once|bool else inventory_hostname }}"
run_once: "{{ download_run_once|bool }}"
- name: Download | save container images - name: Download | save container images
shell: docker save "{{ download.repo }}:{{ download.tag }}" > "{{ fname }}" shell: docker save "{{ download.repo }}:{{ download.tag }}" > "{{ fname }}"
delegate_to: "{{groups['kube-master'][0]}}" delegate_to: "{{groups['kube-master'][0]}}"
run_once: true run_once: true
when: ansible_os_family != "CoreOS" and download_run_once|bool and download.enabled|bool and download.container|bool when: ansible_os_family != "CoreOS" and download_run_once|bool and download.enabled|bool and download.container|bool and container_changed|bool
- name: Download | get container images - name: Download | get container images
synchronize: synchronize:
@ -76,8 +87,8 @@
until: get_task|success until: get_task|success
retries: 4 retries: 4
delay: "{{ retry_stagger | random + 3 }}" delay: "{{ retry_stagger | random + 3 }}"
when: ansible_os_family != "CoreOS" and inventory_hostname != groups['kube-master'][0] and download_run_once|bool and download.enabled|bool and download.container|bool when: ansible_os_family != "CoreOS" and inventory_hostname != groups['kube-master'][0] and download_run_once|bool and download.enabled|bool and download.container|bool and container_changed|bool
- name: Download | load container images - name: Download | load container images
shell: docker load < "{{ fname }}" shell: docker load < "{{ fname }}"
when: ansible_os_family != "CoreOS" and inventory_hostname != groups['kube-master'][0] and download_run_once|bool and download.enabled|bool and download.container|bool when: ansible_os_family != "CoreOS" and inventory_hostname != groups['kube-master'][0] and download_run_once|bool and download.enabled|bool and download.container|bool and container_changed|bool

View file

@ -1,2 +1,8 @@
--- ---
etcd_bin_dir: "{{ local_release_dir }}/etcd/etcd-{{ etcd_version }}-linux-amd64/" etcd_bin_dir: "{{ local_release_dir }}/etcd/etcd-{{ etcd_version }}-linux-amd64/"
etcd_config_dir: /etc/ssl/etcd
etcd_cert_dir: "{{ etcd_config_dir }}/ssl"
etcd_cert_group: root
etcd_script_dir: "{{ bin_dir }}/etcd-scripts"

View file

@ -0,0 +1,80 @@
#!/bin/bash
# Author: Smana smainklh@gmail.com
#
# 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.
set -o errexit
set -o pipefail
usage()
{
cat << EOF
Create self signed certificates
Usage : $(basename $0) -f <config> [-d <ssldir>]
-h | --help : Show this message
-f | --config : Openssl configuration file
-d | --ssldir : Directory where the certificates will be installed
ex :
$(basename $0) -f openssl.conf -d /srv/ssl
EOF
}
# Options parsing
while (($#)); do
case "$1" in
-h | --help) usage; exit 0;;
-f | --config) CONFIG=${2}; shift 2;;
-d | --ssldir) SSLDIR="${2}"; shift 2;;
*)
usage
echo "ERROR : Unknown option"
exit 3
;;
esac
done
if [ -z ${CONFIG} ]; then
echo "ERROR: the openssl configuration file is missing. option -f"
exit 1
fi
if [ -z ${SSLDIR} ]; then
SSLDIR="/etc/ssl/etcd"
fi
tmpdir=$(mktemp -d /tmp/etcd_cacert.XXXXXX)
trap 'rm -rf "${tmpdir}"' EXIT
cd "${tmpdir}"
mkdir -p "${SSLDIR}"
# Root CA
openssl genrsa -out ca-key.pem 2048 > /dev/null 2>&1
openssl req -x509 -new -nodes -key ca-key.pem -days 10000 -out ca.pem -subj "/CN=etcd-ca" > /dev/null 2>&1
# ETCD member
openssl genrsa -out member-key.pem 2048 > /dev/null 2>&1
openssl req -new -key member-key.pem -out member.csr -subj "/CN=etcd-member" -config ${CONFIG} > /dev/null 2>&1
openssl x509 -req -in member.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out member.pem -days 365 -extensions ssl_client -extfile ${CONFIG} > /dev/null 2>&1
# Nodes and Admin
for i in node admin; do
openssl genrsa -out ${i}-key.pem 2048 > /dev/null 2>&1
openssl req -new -key ${i}-key.pem -out ${i}.csr -subj "/CN=kube-${i}" > /dev/null 2>&1
openssl x509 -req -in ${i}.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out ${i}.pem -days 365 -extensions ssl_client -extfile ${CONFIG} > /dev/null 2>&1
done
# Install certs
mv *.pem ${SSLDIR}/

View file

@ -6,21 +6,14 @@
- reload etcd - reload etcd
- wait for etcd up - wait for etcd up
- name: restart etcd-proxy
command: /bin/true
notify:
- etcd | reload systemd
- reload etcd-proxy
- wait for etcd up
- name: etcd | reload systemd - name: etcd | reload systemd
command: systemctl daemon-reload command: systemctl daemon-reload
when: ansible_service_mgr == "systemd" when: ansible_service_mgr == "systemd"
- name: wait for etcd up - name: wait for etcd up
uri: url="http://{% if is_etcd_master %}{{ etcd_address }}{% else %}127.0.0.1{% endif %}:2379/health" uri: url="https://{% if is_etcd_master %}{{ etcd_address }}{% else %}127.0.0.1{% endif %}:2379/health" validate_certs=no
register: result register: result
until: result.status == 200 until: result.status is defined and result.status == 200
retries: 10 retries: 10
delay: 5 delay: 5
@ -30,8 +23,7 @@
state: restarted state: restarted
when: is_etcd_master when: is_etcd_master
- name: reload etcd-proxy - name: set etcd_secret_changed
service: set_fact:
name: etcd-proxy etcd_secret_changed: true
state: restarted
when: is_etcd_proxy

View file

@ -0,0 +1,36 @@
---
- name: "Check_certs | check if the certs have already been generated on first master"
stat:
path: "{{ etcd_cert_dir }}/ca.pem"
delegate_to: "{{groups['etcd'][0]}}"
register: etcdcert_master
run_once: true
- name: "Check_certs | Set default value for 'sync_certs' and 'gen_certs' to false"
set_fact:
sync_certs: false
gen_certs: false
- name: "Check_certs | Set 'sync_certs' and 'gen_certs' to true"
set_fact:
gen_certs: true
when: not etcdcert_master.stat.exists
run_once: true
- name: "Check certs | check if a cert already exists"
stat:
path: "{{ etcd_cert_dir }}/ca.pem"
register: etcdcert
- name: "Check_certs | Set 'sync_certs' to true"
set_fact:
sync_certs: true
when: >-
{%- set certs = {'sync': False} -%}
{%- for server in play_hosts
if (not hostvars[server].etcdcert.stat.exists|default(False)) or
(hostvars[server].etcdcert.stat.checksum|default('') != etcdcert_master.stat.checksum|default('')) -%}
{%- set _ = certs.update({'sync': True}) -%}
{%- endfor -%}
{{ certs.sync }}
run_once: true

View file

@ -1,6 +1,6 @@
--- ---
- name: Configure | Check if member is in cluster - name: Configure | Check if member is in cluster
shell: "etcdctl --no-sync --peers={{ etcd_access_addresses }} member list | grep -q {{ etcd_access_address }}" shell: "{{ bin_dir }}/etcdctl --no-sync --peers={{ etcd_access_addresses }} member list | grep -q {{ etcd_access_address }}"
register: etcd_member_in_cluster register: etcd_member_in_cluster
ignore_errors: true ignore_errors: true
changed_when: false changed_when: false
@ -8,7 +8,7 @@
- name: Configure | Add member to the cluster if it is not there - name: Configure | Add member to the cluster if it is not there
when: is_etcd_master and etcd_member_in_cluster.rc != 0 and etcd_cluster_is_healthy.rc == 0 when: is_etcd_master and etcd_member_in_cluster.rc != 0 and etcd_cluster_is_healthy.rc == 0
shell: "etcdctl --peers={{ etcd_access_addresses }} member add {{ etcd_member_name }} {{ etcd_peer_url }}" shell: "{{ bin_dir }}/etcdctl --peers={{ etcd_access_addresses }} member add {{ etcd_member_name }} {{ etcd_peer_url }}"
- name: Configure | Copy etcd.service systemd file - name: Configure | Copy etcd.service systemd file
template: template:
@ -26,19 +26,3 @@
mode: 0755 mode: 0755
when: ansible_service_mgr in ["sysvinit","upstart"] and ansible_os_family == "Debian" and is_etcd_master when: ansible_service_mgr in ["sysvinit","upstart"] and ansible_os_family == "Debian" and is_etcd_master
notify: restart etcd notify: restart etcd
- name: Configure | Copy etcd-proxy.service systemd file
template:
src: "etcd-proxy-{{ etcd_deployment_type }}.service.j2"
dest: /etc/systemd/system/etcd-proxy.service
backup: yes
when: ansible_service_mgr == "systemd" and is_etcd_proxy
notify: restart etcd-proxy
- name: Configure | Write etcd-proxy initd script
template:
src: "deb-etcd-proxy-{{ etcd_deployment_type }}.initd.j2"
dest: /etc/init.d/etcd-proxy
owner: root
mode: 0755
when: ansible_service_mgr in ["sysvinit","upstart"] and ansible_os_family == "Debian" and is_etcd_proxy
notify: restart etcd-proxy

View file

@ -0,0 +1,112 @@
---
- name: Gen_certs | create etcd script dir
file:
path: "{{ etcd_script_dir }}"
state: directory
owner: root
when: inventory_hostname == groups['etcd'][0]
- name: Gen_certs | create etcd cert dir
file:
path={{ etcd_cert_dir }}
group={{ etcd_cert_group }}
state=directory
owner=root
recurse=yes
- name: Gen_certs | write openssl config
template:
src: "openssl.conf.j2"
dest: "{{ etcd_config_dir }}/openssl.conf"
run_once: yes
delegate_to: "{{groups['etcd'][0]}}"
when: gen_certs|default(false)
- name: Gen_certs | copy certs generation script
copy:
src: "make-ssl-etcd.sh"
dest: "{{ etcd_script_dir }}/make-ssl-etcd.sh"
mode: 0700
run_once: yes
delegate_to: "{{groups['etcd'][0]}}"
when: gen_certs|default(false)
- name: Gen_certs | run cert generation script
command: "{{ etcd_script_dir }}/make-ssl-etcd.sh -f {{ etcd_config_dir }}/openssl.conf -d {{ etcd_cert_dir }}"
run_once: yes
delegate_to: "{{groups['etcd'][0]}}"
when: gen_certs|default(false)
notify: set etcd_secret_changed
- set_fact:
master_certs: ['ca-key.pem', 'admin.pem', 'admin-key.pem', 'member.pem', 'member-key.pem']
node_certs: ['ca.pem', 'node.pem', 'node-key.pem']
- name: Gen_certs | Gather etcd master certs
shell: "tar cfz - -C {{ etcd_cert_dir }} {{ master_certs|join(' ') }} {{ node_certs|join(' ') }}| base64 --wrap=0"
register: etcd_master_cert_data
delegate_to: "{{groups['etcd'][0]}}"
run_once: true
when: sync_certs|default(false)
notify: set etcd_secret_changed
- name: Gen_certs | Gather etcd node certs
shell: "tar cfz - -C {{ etcd_cert_dir }} {{ node_certs|join(' ') }} | base64 --wrap=0"
register: etcd_node_cert_data
delegate_to: "{{groups['etcd'][0]}}"
run_once: true
when: sync_certs|default(false)
notify: set etcd_secret_changed
- name: Gen_certs | Copy certs on masters
shell: "echo '{{etcd_master_cert_data.stdout|quote}}' | base64 -d | tar xz -C {{ etcd_cert_dir }}"
changed_when: false
when: inventory_hostname in groups['etcd'] and sync_certs|default(false) and
inventory_hostname != groups['etcd'][0]
- name: Gen_certs | Copy certs on nodes
shell: "echo '{{etcd_node_cert_data.stdout|quote}}' | base64 -d | tar xz -C {{ etcd_cert_dir }}"
changed_when: false
when: inventory_hostname in groups['k8s-cluster'] and sync_certs|default(false) and
inventory_hostname not in groups['etcd']
- name: Gen_certs | check certificate permissions
file:
path={{ etcd_cert_dir }}
group={{ etcd_cert_group }}
state=directory
owner=kube
recurse=yes
- name: Gen_certs | set permissions on keys
shell: chmod 0600 {{ etcd_cert_dir}}/*key.pem
when: inventory_hostname in groups['etcd']
changed_when: false
- name: Gen_certs | target ca-certificate store file
set_fact:
ca_cert_path: |-
{% if ansible_os_family == "Debian" -%}
/usr/local/share/ca-certificates/etcd-ca.crt
{%- elif ansible_os_family == "RedHat" -%}
/etc/pki/ca-trust/source/anchors/etcd-ca.crt
{%- elif ansible_os_family == "CoreOS" -%}
/etc/ssl/certs/etcd-ca.pem
{%- endif %}
- name: Gen_certs | add CA to trusted CA dir
copy:
src: "{{ etcd_cert_dir }}/ca.pem"
dest: "{{ ca_cert_path }}"
remote_src: true
register: etcd_ca_cert
- name: Gen_certs | update ca-certificates (Debian/Ubuntu/CoreOS)
command: update-ca-certificates
when: etcd_ca_cert.changed and ansible_os_family in ["Debian", "CoreOS"]
- name: Gen_certs | update ca-certificates (RedHat)
command: update-ca-trust extract
when: etcd_ca_cert.changed and ansible_os_family == "RedHat"

View file

@ -1,8 +1,15 @@
--- ---
- include: pre_upgrade.yml
- include: check_certs.yml
- include: gen_certs.yml
- include: install.yml - include: install.yml
when: is_etcd_master
- include: set_cluster_health.yml - include: set_cluster_health.yml
when: is_etcd_master
- include: configure.yml - include: configure.yml
when: is_etcd_master
- include: refresh_config.yml - include: refresh_config.yml
when: is_etcd_master
- name: Ensure etcd is running - name: Ensure etcd is running
service: service:
@ -11,23 +18,11 @@
enabled: yes enabled: yes
when: is_etcd_master when: is_etcd_master
- name: Ensure etcd-proxy is running
service:
name: etcd-proxy
state: started
enabled: yes
when: is_etcd_proxy
- name: Restart etcd if binary changed - name: Restart etcd if binary changed
command: /bin/true command: /bin/true
notify: restart etcd notify: restart etcd
when: etcd_deployment_type == "host" and etcd_copy.stdout_lines and is_etcd_master when: etcd_deployment_type == "host" and etcd_copy.stdout_lines and is_etcd_master
- name: Restart etcd-proxy if binary changed
command: /bin/true
notify: restart etcd-proxy
when: etcd_deployment_type == "host" and etcd_copy.stdout_lines and is_etcd_proxy
# Reload systemd before starting service # Reload systemd before starting service
- meta: flush_handlers - meta: flush_handlers
@ -35,4 +30,6 @@
# initial state of the cluster is in `existing` # initial state of the cluster is in `existing`
# state insted of `new`. # state insted of `new`.
- include: set_cluster_health.yml - include: set_cluster_health.yml
when: is_etcd_master
- include: refresh_config.yml - include: refresh_config.yml
when: is_etcd_master

View file

@ -0,0 +1,34 @@
- name: "Pre-upgrade | check for etcd-proxy unit file"
stat:
path: /etc/systemd/system/etcd-proxy.service
register: kube_apiserver_service_file
- name: "Pre-upgrade | check for etcd-proxy init script"
stat:
path: /etc/init.d/etcd-proxy
register: kube_apiserver_init_script
- name: "Pre-upgrade | stop etcd-proxy if service defined"
service:
name: etcd-proxy
state: stopped
when: (kube_apiserver_service_file.stat.exists|default(False) or kube_apiserver_init_script.stat.exists|default(False))
- name: "Pre-upgrade | remove etcd-proxy service definition"
file:
path: "{{ item }}"
state: absent
when: (kube_apiserver_service_file.stat.exists|default(False) or kube_apiserver_init_script.stat.exists|default(False))
with_items:
- /etc/systemd/system/etcd-proxy.service
- /etc/init.d/etcd-proxy
- name: "Pre-upgrade | find etcd-proxy container"
command: docker ps -aq --filter "name=etcd-proxy*"
register: etcd_proxy_container
ignore_errors: true
- name: "Pre-upgrade | remove etcd-proxy if it exists"
command: "docker rm -f {{item}}"
with_items: "{{etcd_proxy_container.stdout_lines}}"

View file

@ -5,10 +5,3 @@
dest: /etc/etcd.env dest: /etc/etcd.env
notify: restart etcd notify: restart etcd
when: is_etcd_master when: is_etcd_master
- name: Refresh config | Create etcd-proxy config file
template:
src: etcd-proxy.j2
dest: /etc/etcd-proxy.env
notify: restart etcd-proxy
when: is_etcd_proxy

View file

@ -1,6 +1,6 @@
--- ---
- name: Configure | Check if cluster is healthy - name: Configure | Check if cluster is healthy
shell: "etcdctl --peers={{ etcd_access_addresses }} cluster-health | grep -q 'cluster is healthy'" shell: "{{ bin_dir }}/etcdctl --peers={{ etcd_access_addresses }} cluster-health | grep -q 'cluster is healthy'"
register: etcd_cluster_is_healthy register: etcd_cluster_is_healthy
ignore_errors: true ignore_errors: true
changed_when: false changed_when: false

View file

@ -19,8 +19,9 @@ DAEMON={{ docker_bin_dir | default("/usr/bin") }}/docker
DAEMON_EXEC=`basename $DAEMON` DAEMON_EXEC=`basename $DAEMON`
DAEMON_ARGS="run --restart=always --env-file=/etc/etcd.env \ DAEMON_ARGS="run --restart=always --env-file=/etc/etcd.env \
--net=host \ --net=host \
-v /usr/share/ca-certificates/:/etc/ssl/certs:ro \ -v /etc/ssl/certs:/etc/ssl/certs:ro \
-v /var/lib/etcd:/var/lib/etcd:rw \ -v /var/lib/etcd:/var/lib/etcd:rw \
-v {{ etcd_cert_dir }}:{{ etcd_cert_dir }}:ro \
--name={{ etcd_member_name | default("etcd") }} \ --name={{ etcd_member_name | default("etcd") }} \
{{ etcd_image_repo }}:{{ etcd_image_tag }} \ {{ etcd_image_repo }}:{{ etcd_image_tag }} \
{% if etcd_after_v3 %} {% if etcd_after_v3 %}

View file

@ -1,120 +0,0 @@
#!/bin/sh
set -a
### BEGIN INIT INFO
# Provides: etcd-proxy
# Required-Start: $local_fs $network $syslog
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: etcd-proxy
# Description:
# etcd-proxy is a proxy for etcd: distributed, consistent key-value store for shared configuration and service discovery
### END INIT INFO
PATH=/sbin:/usr/sbin:/bin/:/usr/bin
DESC="etcd-proxy"
NAME=etcd-proxy
DAEMON={{ docker_bin_dir | default("/usr/bin") }}/docker
DAEMON_EXEC=`basename $DAEMON`
DAEMON_ARGS="run --restart=always --env-file=/etc/etcd-proxy.env \
--net=host \
--stop-signal=SIGKILL \
-v /usr/share/ca-certificates/:/etc/ssl/certs:ro \
--name={{ etcd_proxy_member_name | default("etcd-proxy") }} \
{{ etcd_image_repo }}:{{ etcd_image_tag }} \
{% if etcd_after_v3 %}
{{ etcd_container_bin_dir }}etcd
{% endif %}"
SCRIPTNAME=/etc/init.d/$NAME
DAEMON_USER=root
STOP_SCHEDULE="${STOP_SCHEDULE:-QUIT/5/TERM/5/KILL/5}"
PID=/var/run/etcd-proxy.pid
# Exit if the binary is not present
[ -x "$DAEMON" ] || exit 0
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions
do_status()
{
status_of_proc -p $PID "$DAEMON" "$NAME" && exit 0 || exit $?
}
# Function that starts the daemon/service
#
do_start()
{
{{ docker_bin_dir | default("/usr/bin") }}/docker rm -f {{ etcd_proxy_member_name | default("etcd-proxy") }} &>/dev/null || true
sleep 1
start-stop-daemon --background --start --quiet --make-pidfile --pidfile $PID --user $DAEMON_USER --exec $DAEMON -- \
$DAEMON_ARGS \
|| return 2
}
#
# Function that stops the daemon/service
#
do_stop()
{
start-stop-daemon --stop --quiet --retry=$STOP_SCHEDULE --pidfile $PID --name $DAEMON_EXEC
RETVAL="$?"
sleep 1
return "$RETVAL"
}
case "$1" in
start)
log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) log_end_msg 0 || exit 0 ;;
2) log_end_msg 1 || exit 1 ;;
esac
;;
stop)
log_daemon_msg "Stopping $DESC" "$NAME"
if do_stop; then
log_end_msg 0
else
log_failure_msg "Can't stop etcd-proxy"
log_end_msg 1
fi
;;
status)
if do_status; then
log_end_msg 0
else
log_failure_msg "etcd-proxy is not running"
log_end_msg 1
fi
;;
restart|force-reload)
log_daemon_msg "Restarting $DESC" "$NAME"
if do_stop; then
if do_start; then
log_end_msg 0
exit 0
else
rc="$?"
fi
else
rc="$?"
fi
log_failure_msg "Can't restart etcd-proxy"
log_end_msg ${rc}
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac

View file

@ -1,110 +0,0 @@
#!/bin/sh
set -a
### BEGIN INIT INFO
# Provides: etcd-proxy
# Required-Start: $local_fs $network $syslog
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: etcd-proxy
# Description:
# etcd-proxy is a proxy for etcd: distributed, consistent key-value store for shared configuration and service discovery
### END INIT INFO
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="etcd-proxy"
NAME=etcd-proxy
DAEMON={{ bin_dir }}/etcd
DAEMON_ARGS=""
SCRIPTNAME=/etc/init.d/$NAME
DAEMON_USER=etcd
STOP_SCHEDULE="${STOP_SCHEDULE:-QUIT/5/TERM/5/KILL/5}"
PID=/var/run/etcd-proxy.pid
# Exit if the binary is not present
[ -x "$DAEMON" ] || exit 0
# Read configuration variable file if it is present
[ -f /etc/etcd-proxy.env ] && . /etc/etcd-proxy.env
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
# and status_of_proc is working.
. /lib/lsb/init-functions
do_status()
{
status_of_proc -p $PID "$DAEMON" "$NAME" && exit 0 || exit $?
}
# Function that starts the daemon/service
#
do_start()
{
start-stop-daemon --background --start --quiet --make-pidfile --pidfile $PID --user $DAEMON_USER --exec $DAEMON -- \
$DAEMON_ARGS \
|| return 2
}
#
# Function that stops the daemon/service
#
do_stop()
{
start-stop-daemon --stop --quiet --retry=$STOP_SCHEDULE --pidfile $PID --name $NAME
RETVAL="$?"
sleep 1
return "$RETVAL"
}
case "$1" in
start)
log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) log_end_msg 0 || exit 0 ;;
2) log_end_msg 1 || exit 1 ;;
esac
;;
stop)
log_daemon_msg "Stopping $DESC" "$NAME"
if do_stop; then
log_end_msg 0
else
log_failure_msg "Can't stop etcd-proxy"
log_end_msg 1
fi
;;
status)
if do_status; then
log_end_msg 0
else
log_failure_msg "etcd-proxy is not running"
log_end_msg 1
fi
;;
restart|force-reload)
log_daemon_msg "Restarting $DESC" "$NAME"
if do_stop; then
if do_start; then
log_end_msg 0
exit 0
else
rc="$?"
fi
else
rc="$?"
fi
log_failure_msg "Can't restart etcd-proxy"
log_end_msg ${rc}
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
exit 3
;;
esac

View file

@ -11,7 +11,8 @@ ExecStart={{ docker_bin_dir | default("/usr/bin") }}/docker run --restart=always
{# TODO(mattymo): Allow docker IP binding and disable in envfile {# TODO(mattymo): Allow docker IP binding and disable in envfile
-p 2380:2380 -p 2379:2379 #} -p 2380:2380 -p 2379:2379 #}
--net=host \ --net=host \
-v /usr/share/ca-certificates/:/etc/ssl/certs:ro \ -v /etc/ssl/certs:/etc/ssl/certs:ro \
-v {{ etcd_cert_dir }}:{{ etcd_cert_dir }}:ro \
-v /var/lib/etcd:/var/lib/etcd:rw \ -v /var/lib/etcd:/var/lib/etcd:rw \
--name={{ etcd_member_name | default("etcd") }} \ --name={{ etcd_member_name | default("etcd") }} \
{{ etcd_image_repo }}:{{ etcd_image_tag }} \ {{ etcd_image_repo }}:{{ etcd_image_tag }} \

View file

@ -1,28 +0,0 @@
[Unit]
Description=etcd-proxy docker wrapper
Wants=docker.socket
After=docker.service
[Service]
User=root
PermissionsStartOnly=true
ExecStart={{ docker_bin_dir | default("/usr/bin") }}/docker run --restart=always \
--env-file=/etc/etcd-proxy.env \
{# TODO(mattymo): Allow docker IP binding and disable in envfile
-p 2380:2380 -p 2379:2379 #}
--net=host \
--stop-signal=SIGKILL \
-v /usr/share/ca-certificates/:/etc/ssl/certs:ro \
--name={{ etcd_proxy_member_name | default("etcd-proxy") }} \
{{ etcd_image_repo }}:{{ etcd_image_tag }} \
{% if etcd_after_v3 %}
{{ etcd_container_bin_dir }}etcd
{% endif %}
ExecStartPre=-{{ docker_bin_dir | default("/usr/bin") }}/docker rm -f {{ etcd_proxy_member_name | default("etcd-proxy") }}
ExecReload={{ docker_bin_dir | default("/usr/bin") }}/docker restart {{ etcd_proxy_member_name | default("etcd-proxy") }}
ExecStop={{ docker_bin_dir | default("/usr/bin") }}/docker stop {{ etcd_proxy_member_name | default("etcd-proxy") }}
Restart=always
RestartSec=15s
[Install]
WantedBy=multi-user.target

View file

@ -1,19 +0,0 @@
[Unit]
Description=etcd-proxy
After=network.target
[Service]
Type=notify
User=etcd
PermissionsStartOnly=true
EnvironmentFile=/etc/etcd-proxy.env
ExecStart={{ bin_dir }}/etcd
ExecStartPre=/bin/mkdir -p /var/lib/etcd-proxy
ExecStartPre=/bin/chown -R etcd: /var/lib/etcd-proxy
NotifyAccess=all
Restart=always
RestartSec=10s
LimitNOFILE=40000
[Install]
WantedBy=multi-user.target

View file

@ -1,5 +0,0 @@
ETCD_DATA_DIR=/var/lib/etcd-proxy
ETCD_PROXY=on
ETCD_LISTEN_CLIENT_URLS={{ etcd_access_endpoint }}
ETCD_NAME={{ etcd_proxy_member_name | default("etcd-proxy") }}
ETCD_INITIAL_CLUSTER={% for host in groups['etcd'] %}etcd{{ loop.index|string }}={{ hostvars[host]['etcd_peer_url'] }}{% if not loop.last %},{% endif %}{% endfor %}

View file

@ -3,14 +3,19 @@ ETCD_ADVERTISE_CLIENT_URLS={{ etcd_client_url }}
ETCD_INITIAL_ADVERTISE_PEER_URLS={{ etcd_peer_url }} ETCD_INITIAL_ADVERTISE_PEER_URLS={{ etcd_peer_url }}
ETCD_INITIAL_CLUSTER_STATE={% if etcd_cluster_is_healthy.rc != 0 | bool %}new{% else %}existing{% endif %} ETCD_INITIAL_CLUSTER_STATE={% if etcd_cluster_is_healthy.rc != 0 | bool %}new{% else %}existing{% endif %}
{% if not is_etcd_proxy %} ETCD_LISTEN_CLIENT_URLS=https://{{ etcd_address }}:2379,https://127.0.0.1:2379
ETCD_LISTEN_CLIENT_URLS=http://{{ etcd_address }}:2379,http://127.0.0.1:2379
{% else %}
ETCD_LISTEN_CLIENT_URLS=http://{{ etcd_address }}:2379
{% endif %}
ETCD_ELECTION_TIMEOUT=10000 ETCD_ELECTION_TIMEOUT=10000
ETCD_INITIAL_CLUSTER_TOKEN=k8s_etcd ETCD_INITIAL_CLUSTER_TOKEN=k8s_etcd
ETCD_LISTEN_PEER_URLS=http://{{ etcd_address }}:2380 ETCD_LISTEN_PEER_URLS=https://{{ etcd_address }}:2380
ETCD_NAME={{ etcd_member_name }} ETCD_NAME={{ etcd_member_name }}
ETCD_PROXY=off ETCD_PROXY=off
ETCD_INITIAL_CLUSTER={% for host in groups['etcd'] %}etcd{{ loop.index|string }}={{ hostvars[host]['etcd_peer_url'] }}{% if not loop.last %},{% endif %}{% endfor %} ETCD_INITIAL_CLUSTER={{ etcd_peer_addresses }}
# TLS settings
ETCD_TRUSTED_CA_FILE={{ etcd_cert_dir }}/ca.pem
ETCD_CERT_FILE={{ etcd_cert_dir }}/node.pem
ETCD_KEY_FILE={{ etcd_cert_dir }}/node-key.pem
ETCD_PEER_TRUSTED_CA_FILE={{ etcd_cert_dir }}/ca.pem
ETCD_PEER_CERT_FILE={{ etcd_cert_dir }}/member.pem
ETCD_PEER_KEY_FILE={{ etcd_cert_dir }}/member-key.pem
ETCD_PEER_CLIENT_CERT_AUTH=true

View file

@ -0,0 +1,39 @@
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
[ ssl_client ]
extendedKeyUsage = clientAuth, serverAuth
basicConstraints = CA:FALSE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
subjectAltName = @alt_names
[ v3_ca ]
basicConstraints = CA:TRUE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
authorityKeyIdentifier=keyid:always,issuer
[alt_names]
DNS.1 = localhost
{% for host in groups['etcd'] %}
DNS.{{ 1 + loop.index }} = {{ host }}
{% endfor %}
{% if loadbalancer_apiserver is defined and apiserver_loadbalancer_domain_name is defined %}
{% set idx = groups['etcd'] | length | int + 1 %}
DNS.{{ idx | string }} = {{ apiserver_loadbalancer_domain_name }}
{% endif %}
{% for host in groups['etcd'] %}
IP.{{ 2 * loop.index - 1 }} = {{ hostvars[host]['access_ip'] | default(hostvars[host]['ansible_default_ipv4']['address']) }}
IP.{{ 2 * loop.index }} = {{ hostvars[host]['ip'] | default(hostvars[host]['ansible_default_ipv4']['address']) }}
{% endfor %}
{% set idx = groups['etcd'] | length | int * 2 + 1 %}
IP.{{ idx }} = 127.0.0.1

View file

@ -0,0 +1,15 @@
# Versions
kubedns_version: 1.7
kubednsmasq_version: 1.3
exechealthz_version: 1.1
# Images
kubedns_image_repo: "gcr.io/google_containers/kubedns-amd64"
kubedns_image_tag: "{{ kubedns_version }}"
kubednsmasq_image_repo: "gcr.io/google_containers/kube-dnsmasq-amd64"
kubednsmasq_image_tag: "{{ kubednsmasq_version }}"
exechealthz_image_repo: "gcr.io/google_containers/exechealthz-amd64"
exechealthz_image_tag: "{{ exechealthz_version }}"
# SSL
etcd_cert_dir: "/etc/ssl/etcd/ssl"

View file

@ -5,6 +5,9 @@
- name: Start of Calico policy controller - name: Start of Calico policy controller
kube: kube:
name: "calico-policy-controller"
kubectl: "{{bin_dir}}/kubectl" kubectl: "{{bin_dir}}/kubectl"
filename: /etc/kubernetes/calico-policy-controller.yml filename: "/etc/kubernetes/calico-policy-controller.yml"
namespace: "kube-system"
resource: "rs"
when: inventory_hostname == groups['kube-master'][0] when: inventory_hostname == groups['kube-master'][0]

View file

@ -18,6 +18,6 @@
with_items: "{{ manifests.results }}" with_items: "{{ manifests.results }}"
when: inventory_hostname == groups['kube-master'][0] when: inventory_hostname == groups['kube-master'][0]
- include: tasks/calico-policy-controller.yml - include: tasks/calico-policy-controller.yml
when: enable_network_policy is defined and enable_network_policy == True when: ( enable_network_policy is defined and enable_network_policy == True ) or
( kube_network_plugin == 'canal' )

View file

@ -26,7 +26,13 @@ spec:
image: calico/kube-policy-controller:latest image: calico/kube-policy-controller:latest
env: env:
- name: ETCD_ENDPOINTS - name: ETCD_ENDPOINTS
value: "{{ etcd_endpoint }}" value: "{{ etcd_access_endpoint }}"
- name: ETCD_CA_CERT_FILE
value: "{{ etcd_cert_dir }}/ca.pem"
- name: ETCD_CERT_FILE
value: "{{ etcd_cert_dir }}/node.pem"
- name: ETCD_KEY_FILE
value: "{{ etcd_cert_dir }}/node-key.pem"
# Location of the Kubernetes API - this shouldn't need to be # Location of the Kubernetes API - this shouldn't need to be
# changed so long as it is used in conjunction with # changed so long as it is used in conjunction with
# CONFIGURE_ETC_HOSTS="true". # CONFIGURE_ETC_HOSTS="true".
@ -38,3 +44,11 @@ spec:
# This removes the need for KubeDNS to resolve the Service. # This removes the need for KubeDNS to resolve the Service.
- name: CONFIGURE_ETC_HOSTS - name: CONFIGURE_ETC_HOSTS
value: "true" value: "true"
volumeMounts:
- mountPath: {{ etcd_cert_dir }}
name: etcd-certs
readOnly: true
volumes:
- hostPath:
path: {{ etcd_cert_dir }}
name: etcd-certs

View file

@ -21,7 +21,7 @@ spec:
spec: spec:
containers: containers:
- name: kubedns - name: kubedns
image: gcr.io/google_containers/kubedns-amd64:1.7 image: "{{ kubedns_image_repo }}:{{ kubedns_image_tag }}"
resources: resources:
# TODO: Set memory limits when we've profiled the container for large # TODO: Set memory limits when we've profiled the container for large
# clusters, then set request = limit to keep this container in # clusters, then set request = limit to keep this container in
@ -63,7 +63,7 @@ spec:
name: dns-tcp-local name: dns-tcp-local
protocol: TCP protocol: TCP
- name: dnsmasq - name: dnsmasq
image: gcr.io/google_containers/kube-dnsmasq-amd64:1.3 image: "{{ kubednsmasq_image_repo }}:{{ kubednsmasq_image_tag }}"
args: args:
- --log-facility=- - --log-facility=-
- --cache-size=1000 - --cache-size=1000
@ -77,7 +77,7 @@ spec:
name: dns-tcp name: dns-tcp
protocol: TCP protocol: TCP
- name: healthz - name: healthz
image: gcr.io/google_containers/exechealthz-amd64:1.1 image: "{{ exechealthz_image_repo }}:{{ exechealthz_image_tag }}"
resources: resources:
# keep request = limit to keep this container in guaranteed class # keep request = limit to keep this container in guaranteed class
limits: limits:

View file

@ -0,0 +1,17 @@
- name: Create canal ConfigMap
run_once: true
kube:
name: "canal-config"
kubectl: "{{bin_dir}}/kubectl"
filename: "/etc/kubernetes/canal-config.yaml"
resource: "configmap"
namespace: "kube-system"
- name: Start flannel and calico-node
run_once: true
kube:
name: "canal-node"
kubectl: "{{bin_dir}}/kubectl"
filename: "/etc/kubernetes/canal-node.yaml"
resource: "ds"
namespace: "kube-system"

View file

@ -0,0 +1,4 @@
---
dependencies:
- role: kubernetes-apps/network_plugin/canal
when: kube_network_plugin == 'canal'

View file

@ -10,3 +10,27 @@ kube_users_dir: "{{ kube_config_dir }}/users"
# An experimental dev/test only dynamic volumes provisioner, # An experimental dev/test only dynamic volumes provisioner,
# for PetSets. Works for kube>=v1.3 only. # for PetSets. Works for kube>=v1.3 only.
kube_hostpath_dynamic_provisioner: "false" kube_hostpath_dynamic_provisioner: "false"
# This is where you can drop yaml/json files and the kubelet will run those
# pods on startup
kube_manifest_dir: "{{ kube_config_dir }}/manifests"
# This directory is where all the additional config stuff goes
# the kubernetes normally puts in /srv/kubernets.
# This puts them in a sane location.
# Editting this value will almost surely break something. Don't
# change it. Things like the systemd scripts are hard coded to
# look in here. Don't do it.
kube_config_dir: /etc/kubernetes
# change to 0.0.0.0 to enable insecure access from anywhere (not recommended)
kube_apiserver_insecure_bind_address: 127.0.0.1
# Logging directory (sysvinit systems)
kube_log_dir: "/var/log/kubernetes"
# ETCD cert dir for connecting apiserver to etcd
etcd_config_dir: /etc/ssl/etcd
etcd_cert_dir: "{{ etcd_config_dir }}/ssl"

View file

@ -3,6 +3,8 @@ kind: Pod
metadata: metadata:
name: kube-apiserver name: kube-apiserver
namespace: kube-system namespace: kube-system
labels:
k8s-app: kube-apiserver
spec: spec:
hostNetwork: true hostNetwork: true
containers: containers:
@ -14,9 +16,12 @@ spec:
- --advertise-address={{ ip | default(ansible_default_ipv4.address) }} - --advertise-address={{ ip | default(ansible_default_ipv4.address) }}
- --etcd-servers={{ etcd_access_endpoint }} - --etcd-servers={{ etcd_access_endpoint }}
- --etcd-quorum-read=true - --etcd-quorum-read=true
- --etcd-cafile={{ etcd_cert_dir }}/ca.pem
- --etcd-certfile={{ etcd_cert_dir }}/node.pem
- --etcd-keyfile={{ etcd_cert_dir }}/node-key.pem
- --insecure-bind-address={{ kube_apiserver_insecure_bind_address }} - --insecure-bind-address={{ kube_apiserver_insecure_bind_address }}
- --apiserver-count={{ kube_apiserver_count }} - --apiserver-count={{ kube_apiserver_count }}
- --admission-control=NamespaceLifecycle,NamespaceExists,LimitRanger,ServiceAccount,ResourceQuota - --admission-control=NamespaceLifecycle,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota
- --service-cluster-ip-range={{ kube_service_addresses }} - --service-cluster-ip-range={{ kube_service_addresses }}
- --client-ca-file={{ kube_cert_dir }}/ca.pem - --client-ca-file={{ kube_cert_dir }}/ca.pem
- --basic-auth-file={{ kube_users_dir }}/known_users.csv - --basic-auth-file={{ kube_users_dir }}/known_users.csv
@ -50,6 +55,9 @@ spec:
- mountPath: /etc/ssl/certs - mountPath: /etc/ssl/certs
name: ssl-certs-host name: ssl-certs-host
readOnly: true readOnly: true
- mountPath: {{ etcd_cert_dir }}
name: etcd-certs
readOnly: true
- mountPath: /var/log/ - mountPath: /var/log/
name: logfile name: logfile
volumes: volumes:
@ -59,6 +67,9 @@ spec:
- hostPath: - hostPath:
path: /etc/ssl/certs/ path: /etc/ssl/certs/
name: ssl-certs-host name: ssl-certs-host
- hostPath:
path: {{ etcd_cert_dir }}
name: etcd-certs
- hostPath: - hostPath:
path: /var/log/ path: /var/log/
name: logfile name: logfile

View file

@ -3,6 +3,8 @@ kind: Pod
metadata: metadata:
name: kube-controller-manager name: kube-controller-manager
namespace: kube-system namespace: kube-system
labels:
k8s-app: kube-controller
spec: spec:
hostNetwork: true hostNetwork: true
containers: containers:

View file

@ -3,6 +3,8 @@ kind: Pod
metadata: metadata:
name: kube-scheduler name: kube-scheduler
namespace: kube-system namespace: kube-system
labels:
k8s-app: kube-scheduler
spec: spec:
hostNetwork: true hostNetwork: true
containers: containers:

View file

@ -1,6 +1,13 @@
# This is where all the cert scripts and certs will be located # This is where all the cert scripts and certs will be located
kube_cert_dir: "{{ kube_config_dir }}/ssl" kube_cert_dir: "{{ kube_config_dir }}/ssl"
# change to 0.0.0.0 to enable insecure access from anywhere (not recommended)
kube_apiserver_insecure_bind_address: 127.0.0.1
# This is where you can drop yaml/json files and the kubelet will run those
# pods on startup
kube_manifest_dir: "{{ kube_config_dir }}/manifests"
dns_domain: "{{ cluster_name }}" dns_domain: "{{ cluster_name }}"
# resolv.conf to base dns config # resolv.conf to base dns config
@ -15,5 +22,16 @@ kube_proxy_masquerade_all: true
# - extensions/v1beta1/daemonsets=true # - extensions/v1beta1/daemonsets=true
# - extensions/v1beta1/deployments=true # - extensions/v1beta1/deployments=true
# Logging directory (sysvinit systems)
kube_log_dir: "/var/log/kubernetes"
# This directory is where all the additional config stuff goes
# the kubernetes normally puts in /srv/kubernets.
# This puts them in a sane location.
# Editting this value will almost surely break something. Don't
# change it. Things like the systemd scripts are hard coded to
# look in here. Don't do it.
kube_config_dir: /etc/kubernetes
nginx_image_repo: nginx nginx_image_repo: nginx
nginx_image_tag: 1.11.4-alpine nginx_image_tag: 1.11.4-alpine

View file

@ -2,4 +2,6 @@
dependencies: dependencies:
- role: download - role: download
file: "{{ downloads.hyperkube }}" file: "{{ downloads.hyperkube }}"
- role: download
file: "{{ downloads.pod_infra }}"
- role: kubernetes/secrets - role: kubernetes/secrets

View file

@ -11,6 +11,13 @@
owner: kube owner: kube
when: kube_network_plugin == "calico" when: kube_network_plugin == "calico"
- name: Write Canal cni config
template:
src: "cni-canal.conf.j2"
dest: "/etc/cni/net.d/10-canal.conf"
owner: kube
when: kube_network_plugin == "canal"
- name: Write kubelet config file - name: Write kubelet config file
template: src=kubelet.j2 dest={{ kube_config_dir }}/kubelet.env backup=yes template: src=kubelet.j2 dest={{ kube_config_dir }}/kubelet.env backup=yes
notify: notify:

View file

@ -1,6 +1,10 @@
{ {
"name": "calico-k8s-network", "name": "calico-k8s-network",
"type": "calico", "type": "calico",
"etcd_endpoints": "{{ etcd_access_endpoint }}",
"etcd_cert_file": "{{ etcd_cert_dir }}/node.pem",
"etcd_key_file": "{{ etcd_cert_dir }}/node-key.pem",
"etcd_ca_cert_file": "{{ etcd_cert_dir }}/ca.pem",
"log_level": "info", "log_level": "info",
"ipam": { "ipam": {
"type": "calico-ipam" "type": "calico-ipam"

View file

@ -0,0 +1,15 @@
{
"name": "canal-k8s-network",
"type": "flannel",
"delegate": {
"type": "calico",
"etcd_endpoints": "{{ etcd_access_endpoint }}",
"log_level": "info",
"policy": {
"type": "k8s"
},
"kubernetes": {
"kubeconfig": "{{ kube_config_dir }}/node-kubeconfig.yaml"
}
}
}

View file

@ -20,13 +20,13 @@ KUBELET_REGISTER_NODE="--register-node=false"
{% endif %} {% endif %}
# location of the api-server # location of the api-server
{% if dns_setup|bool and skip_dnsmasq|bool %} {% if dns_setup|bool and skip_dnsmasq|bool %}
KUBELET_ARGS="--cluster_dns={{ skydns_server }} --cluster_domain={{ dns_domain }} --kubeconfig={{ kube_config_dir}}/node-kubeconfig.yaml --config={{ kube_manifest_dir }} --resolv-conf={{ kube_resolv_conf }}" KUBELET_ARGS="--cluster_dns={{ skydns_server }} --cluster_domain={{ dns_domain }} --kubeconfig={{ kube_config_dir}}/node-kubeconfig.yaml --config={{ kube_manifest_dir }} --resolv-conf={{ kube_resolv_conf }} --pod-infra-container-image={{ pod_infra_image_repo }}:{{ pod_infra_image_tag }}"
{% elif dns_setup|bool %} {% elif dns_setup|bool %}
KUBELET_ARGS="--cluster_dns={{ dns_server }} --cluster_domain={{ dns_domain }} --kubeconfig={{ kube_config_dir}}/node-kubeconfig.yaml --config={{ kube_manifest_dir }} --resolv-conf={{ kube_resolv_conf }}" KUBELET_ARGS="--cluster_dns={{ dns_server }} --cluster_domain={{ dns_domain }} --kubeconfig={{ kube_config_dir}}/node-kubeconfig.yaml --config={{ kube_manifest_dir }} --resolv-conf={{ kube_resolv_conf }} --pod-infra-container-image={{ pod_infra_image_repo }}:{{ pod_infra_image_tag }}"
{% else %} {% else %}
KUBELET_ARGS="--kubeconfig={{ kube_config_dir}}/kubelet.kubeconfig --config={{ kube_manifest_dir }}" KUBELET_ARGS="--kubeconfig={{ kube_config_dir}}/kubelet.kubeconfig --config={{ kube_manifest_dir }} --pod-infra-container-image={{ pod_infra_image_repo }}:{{ pod_infra_image_tag }}"
{% endif %} {% endif %}
{% if kube_network_plugin is defined and kube_network_plugin in ["calico", "weave"] %} {% if kube_network_plugin is defined and kube_network_plugin in ["calico", "weave", "canal"] %}
KUBELET_NETWORK_PLUGIN="--network-plugin=cni --network-plugin-dir=/etc/cni/net.d" KUBELET_NETWORK_PLUGIN="--network-plugin=cni --network-plugin-dir=/etc/cni/net.d"
{% elif kube_network_plugin is defined and kube_network_plugin == "weave" %} {% elif kube_network_plugin is defined and kube_network_plugin == "weave" %}
DOCKER_SOCKET="--docker-endpoint=unix:/var/run/weave/weave.sock" DOCKER_SOCKET="--docker-endpoint=unix:/var/run/weave/weave.sock"

View file

@ -3,6 +3,8 @@ kind: Pod
metadata: metadata:
name: kube-proxy name: kube-proxy
namespace: kube-system namespace: kube-system
labels:
k8s-app: kube-proxy
spec: spec:
hostNetwork: true hostNetwork: true
containers: containers:

View file

@ -3,6 +3,8 @@ kind: Pod
metadata: metadata:
name: nginx-proxy name: nginx-proxy
namespace: kube-system namespace: kube-system
labels:
k8s-app: kube-nginx
spec: spec:
hostNetwork: true hostNetwork: true
containers: containers:

View file

@ -21,8 +21,7 @@ kube_log_dir: "/var/log/kubernetes"
# pods on startup # pods on startup
kube_manifest_dir: "{{ kube_config_dir }}/manifests" kube_manifest_dir: "{{ kube_config_dir }}/manifests"
# change to 0.0.0.0 to enable insecure access from anywhere (not recommended) epel_rpm_download_url: "https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm"
kube_apiserver_insecure_bind_address: 127.0.0.1
common_required_pkgs: common_required_pkgs:
- python-httplib2 - python-httplib2
@ -46,3 +45,6 @@ openstack_username: "{{ lookup('env','OS_USERNAME') }}"
openstack_password: "{{ lookup('env','OS_PASSWORD') }}" openstack_password: "{{ lookup('env','OS_PASSWORD') }}"
openstack_region: "{{ lookup('env','OS_REGION_NAME') }}" openstack_region: "{{ lookup('env','OS_REGION_NAME') }}"
openstack_tenant_id: "{{ lookup('env','OS_TENANT_ID') }}" openstack_tenant_id: "{{ lookup('env','OS_TENANT_ID') }}"
# All clients access each node individually, instead of using a load balancer.
etcd_multiaccess: true

View file

@ -74,7 +74,7 @@
with_items: with_items:
- "/etc/cni/net.d" - "/etc/cni/net.d"
- "/opt/cni/bin" - "/opt/cni/bin"
when: kube_network_plugin in ["calico", "weave"] and "{{ inventory_hostname in groups['k8s-cluster'] }}" when: kube_network_plugin in ["calico", "weave", "canal"] and "{{ inventory_hostname in groups['k8s-cluster'] }}"
- name: Update package management cache (YUM) - name: Update package management cache (YUM)
yum: update_cache=yes name='*' yum: update_cache=yes name='*'
@ -91,7 +91,7 @@
changed_when: False changed_when: False
- name: Install epel-release on RedHat/CentOS - name: Install epel-release on RedHat/CentOS
shell: rpm -qa | grep epel-release || rpm -ivh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm shell: rpm -qa | grep epel-release || rpm -ivh {{ epel_rpm_download_url }}
when: ansible_distribution in ["CentOS","RedHat"] and when: ansible_distribution in ["CentOS","RedHat"] and
ansible_distribution_major_version >= 7 ansible_distribution_major_version >= 7
changed_when: False changed_when: False

View file

@ -23,14 +23,14 @@
- set_fact: etcd_address="{{ ip | default(ansible_default_ipv4['address']) }}" - set_fact: etcd_address="{{ ip | default(ansible_default_ipv4['address']) }}"
- set_fact: etcd_access_address="{{ access_ip | default(etcd_address) }}" - set_fact: etcd_access_address="{{ access_ip | default(etcd_address) }}"
- set_fact: etcd_peer_url="http://{{ etcd_access_address }}:2380" - set_fact: etcd_peer_url="https://{{ etcd_access_address }}:2380"
- set_fact: etcd_client_url="http://{{ etcd_access_address }}:2379" - set_fact: etcd_client_url="https://{{ etcd_access_address }}:2379"
- set_fact: etcd_authority="127.0.0.1:2379" - set_fact: etcd_authority="127.0.0.1:2379"
- set_fact: etcd_endpoint="http://{{ etcd_authority }}" - set_fact: etcd_endpoint="https://{{ etcd_authority }}"
- set_fact: - set_fact:
etcd_access_addresses: |- etcd_access_addresses: |-
{% for item in groups['etcd'] -%} {% for item in groups['etcd'] -%}
http://{{ hostvars[item].etcd_access_address }}:2379{% if not loop.last %},{% endif %} https://{{ item }}:2379{% if not loop.last %},{% endif %}
{%- endfor %} {%- endfor %}
- set_fact: etcd_access_endpoint="{% if etcd_multiaccess %}{{ etcd_access_addresses }}{% else %}{{ etcd_endpoint }}{% endif %}" - set_fact: etcd_access_endpoint="{% if etcd_multiaccess %}{{ etcd_access_addresses }}{% else %}{{ etcd_endpoint }}{% endif %}"
- set_fact: - set_fact:
@ -39,12 +39,10 @@
{% if inventory_hostname == host %}{{"etcd"+loop.index|string }}{% endif %} {% if inventory_hostname == host %}{{"etcd"+loop.index|string }}{% endif %}
{% endfor %} {% endfor %}
- set_fact: - set_fact:
etcd_proxy_member_name: |- etcd_peer_addresses: |-
{% for host in groups['k8s-cluster'] %} {% for item in groups['etcd'] -%}
{% if inventory_hostname == host %}{{"etcd-proxy"+loop.index|string }}{% endif %} {{ "etcd"+loop.index|string }}=https://{{ hostvars[item].access_ip | default(hostvars[item].ip | default(hostvars[item].ansible_default_ipv4['address'])) }}:2380{% if not loop.last %},{% endif %}
{% endfor %} {%- endfor %}
- set_fact:
is_etcd_proxy: "{{ inventory_hostname in groups['k8s-cluster'] }}"
- set_fact: - set_fact:
is_etcd_master: "{{ inventory_hostname in groups['etcd'] }}" is_etcd_master: "{{ inventory_hostname in groups['etcd'] }}"
- set_fact: - set_fact:

View file

@ -6,3 +6,16 @@ kube_token_dir: "{{ kube_config_dir }}/tokens"
# This is where to save basic auth file # This is where to save basic auth file
kube_users_dir: "{{ kube_config_dir }}/users" kube_users_dir: "{{ kube_config_dir }}/users"
# This directory is where all the additional config stuff goes
# the kubernetes normally puts in /srv/kubernets.
# This puts them in a sane location.
# Editting this value will almost surely break something. Don't
# change it. Things like the systemd scripts are hard coded to
# look in here. Don't do it.
kube_config_dir: /etc/kubernetes
# This directory is where all the additional scripts go
# that Kubernetes normally puts in /srv/kubernetes.
# This puts them in a sane location
kube_script_dir: "{{ bin_dir }}/kubernetes-scripts"

View file

@ -27,7 +27,7 @@
sync_tokens: true sync_tokens: true
when: >- when: >-
{%- set tokens = {'sync': False} -%} {%- set tokens = {'sync': False} -%}
{%- for server in groups['kube-master'] {%- for server in groups['kube-master'] | intersect(play_hosts)
if (not hostvars[server].known_tokens.stat.exists) or if (not hostvars[server].known_tokens.stat.exists) or
(hostvars[server].known_tokens.stat.checksum != known_tokens_master.stat.checksum|default('')) -%} (hostvars[server].known_tokens.stat.checksum != known_tokens_master.stat.checksum|default('')) -%}
{%- set _ = tokens.update({'sync': True}) -%} {%- set _ = tokens.update({'sync': True}) -%}

View file

@ -27,31 +27,30 @@
master_certs: ['ca-key.pem', 'admin.pem', 'admin-key.pem', 'apiserver-key.pem', 'apiserver.pem'] master_certs: ['ca-key.pem', 'admin.pem', 'admin-key.pem', 'apiserver-key.pem', 'apiserver.pem']
node_certs: ['ca.pem', 'node.pem', 'node-key.pem'] node_certs: ['ca.pem', 'node.pem', 'node-key.pem']
- name: Gen_certs | Get the certs from first master - name: Gen_certs | Gather master certs
slurp: shell: "tar cfz - -C {{ kube_cert_dir }} {{ master_certs|join(' ') }} {{ node_certs|join(' ') }} | base64 --wrap=0"
src: "{{ kube_cert_dir }}/{{ item }}" register: master_cert_data
delegate_to: "{{groups['kube-master'][0]}}" delegate_to: "{{groups['kube-master'][0]}}"
register: slurp_certs
with_items: '{{ master_certs + node_certs }}'
when: sync_certs|default(false)
run_once: true run_once: true
notify: set secret_changed when: sync_certs|default(false)
- name: Gen_certs | Gather node certs
shell: "tar cfz - -C {{ kube_cert_dir }} {{ node_certs|join(' ') }} | base64 --wrap=0"
register: node_cert_data
delegate_to: "{{groups['kube-master'][0]}}"
run_once: true
when: sync_certs|default(false)
- name: Gen_certs | Copy certs on masters - name: Gen_certs | Copy certs on masters
copy: shell: "echo '{{master_cert_data.stdout|quote}}' | base64 -d | tar xz -C {{ kube_cert_dir }}"
content: "{{ item.content|b64decode }}" changed_when: false
dest: "{{ item.source }}"
with_items: '{{slurp_certs.results}}'
when: inventory_hostname in groups['kube-master'] and sync_certs|default(false) and when: inventory_hostname in groups['kube-master'] and sync_certs|default(false) and
inventory_hostname != groups['kube-master'][0] inventory_hostname != groups['kube-master'][0]
- name: Gen_certs | Copy certs on nodes - name: Gen_certs | Copy certs on nodes
copy: shell: "echo '{{node_cert_data.stdout|quote}}' | base64 -d | tar xz -C {{ kube_cert_dir }}"
content: "{{ item.content|b64decode }}" changed_when: false
dest: "{{ item.source }}" when: inventory_hostname in groups['kube-node'] and sync_certs|default(false) and
with_items: '{{slurp_certs.results}}'
when: item.item in node_certs and
inventory_hostname in groups['kube-node'] and sync_certs|default(false) and
inventory_hostname != groups['kube-master'][0] inventory_hostname != groups['kube-master'][0]
- name: Gen_certs | check certificate permissions - name: Gen_certs | check certificate permissions
@ -66,21 +65,21 @@
when: inventory_hostname in groups['kube-master'] when: inventory_hostname in groups['kube-master']
changed_when: false changed_when: false
- name: Gen_certs | target ca-certificates directory - name: Gen_certs | target ca-certificates path
set_fact: set_fact:
ca_cert_dir: |- ca_cert_path: |-
{% if ansible_os_family == "Debian" -%} {% if ansible_os_family == "Debian" -%}
/usr/local/share/ca-certificates /usr/local/share/ca-certificates/kube-ca.crt
{%- elif ansible_os_family == "RedHat" -%} {%- elif ansible_os_family == "RedHat" -%}
/etc/pki/ca-trust/source/anchors /etc/pki/ca-trust/source/anchors/kube-ca.crt
{%- elif ansible_os_family == "CoreOS" -%} {%- elif ansible_os_family == "CoreOS" -%}
/etc/ssl/certs /etc/ssl/certs/kube-ca.pem
{%- endif %} {%- endif %}
- name: Gen_certs | add CA to trusted CA dir - name: Gen_certs | add CA to trusted CA dir
copy: copy:
src: "{{ kube_cert_dir }}/ca.pem" src: "{{ kube_cert_dir }}/ca.pem"
dest: "{{ ca_cert_dir }}/kube-ca.crt" dest: "{{ ca_cert_path }}"
remote_src: true remote_src: true
register: kube_ca_cert register: kube_ca_cert
@ -88,7 +87,7 @@
command: update-ca-certificates command: update-ca-certificates
when: kube_ca_cert.changed and ansible_os_family in ["Debian", "CoreOS"] when: kube_ca_cert.changed and ansible_os_family in ["Debian", "CoreOS"]
- name: Gen_certs | update ca-certificatesa (RedHat) - name: Gen_certs | update ca-certificates (RedHat)
command: update-ca-trust extract command: update-ca-trust extract
when: kube_ca_cert.changed and ansible_os_family == "RedHat" when: kube_ca_cert.changed and ansible_os_family == "RedHat"

View file

@ -43,20 +43,15 @@
delegate_to: "{{groups['kube-master'][0]}}" delegate_to: "{{groups['kube-master'][0]}}"
when: sync_tokens|default(false) when: sync_tokens|default(false)
- name: Gen_tokens | Get the tokens from first master - name: Gen_tokens | Gather tokens
slurp: shell: "tar cfz - {{ tokens_list.stdout_lines | join(' ') }} | base64 --wrap=0"
src: "{{ item }}" register: tokens_data
register: slurp_tokens
with_items: '{{tokens_list.stdout_lines}}'
run_once: true
delegate_to: "{{groups['kube-master'][0]}}" delegate_to: "{{groups['kube-master'][0]}}"
run_once: true
when: sync_tokens|default(false) when: sync_tokens|default(false)
notify: set secret_changed
- name: Gen_tokens | Copy tokens on masters - name: Gen_tokens | Copy tokens on masters
copy: shell: "echo '{{ tokens_data.stdout|quote }}' | base64 -d | tar xz -C /"
content: "{{ item.content|b64decode }}" changed_when: false
dest: "{{ item.source }}"
with_items: '{{slurp_tokens.results}}'
when: inventory_hostname in groups['kube-master'] and sync_tokens|default(false) and when: inventory_hostname in groups['kube-master'] and sync_tokens|default(false) and
inventory_hostname != groups['kube-master'][0] inventory_hostname != groups['kube-master'][0]

View file

@ -8,3 +8,6 @@ ipip: false
# Set to true if you want your calico cni binaries to overwrite the # Set to true if you want your calico cni binaries to overwrite the
# ones from hyperkube while leaving other cni plugins intact. # ones from hyperkube while leaving other cni plugins intact.
overwrite_hyperkube_cni: true overwrite_hyperkube_cni: true
calico_cert_dir: /etc/calico/certs
etcd_cert_dir: /etc/ssl/etcd/ssl

View file

@ -12,6 +12,24 @@
- meta: flush_handlers - meta: flush_handlers
- name: Calico | Create calico certs directory
file:
dest: "{{ calico_cert_dir }}"
state: directory
mode: 0750
owner: root
group: root
- name: Calico | Link etcd certificates for calico-node
file:
src: "{{ etcd_cert_dir }}/{{ item.s }}"
dest: "{{ calico_cert_dir }}/{{ item.d }}"
state: hard
with_items:
- {s: "ca.pem", d: "ca_cert.crt"}
- {s: "node.pem", d: "cert.crt"}
- {s: "node-key.pem", d: "key.pem"}
- name: Calico | Install calicoctl container script - name: Calico | Install calicoctl container script
template: template:
src: calicoctl-container.j2 src: calicoctl-container.j2
@ -41,59 +59,95 @@
when: "{{ overwrite_hyperkube_cni|bool }}" when: "{{ overwrite_hyperkube_cni|bool }}"
- name: Calico | wait for etcd - name: Calico | wait for etcd
uri: url=http://localhost:2379/health uri: url=https://localhost:2379/health validate_certs=no
register: result register: result
until: result.status == 200 until: result.status == 200 or result.status == 401
retries: 10 retries: 10
delay: 5 delay: 5
when: inventory_hostname in groups['kube-master'] delegate_to: "{{groups['etcd'][0]}}"
- name: Calico | Check if calico network pool has already been configured
uri:
url: "{{ etcd_endpoint }}/v2/keys/calico/v1/ipam/v4/pool"
return_content: yes
status_code: 200,404
register: calico_conf
run_once: true run_once: true
- name: Calico | Define ipip pool argument - name: Calico | Check if calico network pool has already been configured
command: |-
curl \
--cacert {{ etcd_cert_dir }}/ca.pem \
--cert {{ etcd_cert_dir}}/admin.pem \
--key {{ etcd_cert_dir }}/admin-key.pem \
https://localhost:2379/v2/keys/calico/v1/ipam/v4/pool
register: calico_conf
delegate_to: "{{groups['etcd'][0]}}"
run_once: true
- name: Calico | Check calicoctl version
run_once: true
set_fact:
legacy_calicoctl: "{{ calicoctl_image_tag | version_compare('v1.0.0', '<') }}"
- name: Calico | Configure calico network pool
shell: >
echo '{
"kind": "ipPool",
"spec": {"disabled": false, "ipip": {"enabled": {{ cloud_provider is defined or ipip }}},
"nat-outgoing": {{ nat_outgoing|default(false) and not peer_with_router|default(false) }}},
"apiVersion": "v1",
"metadata": {"cidr": "{{ kube_pods_subnet }}"}
}'
| {{ bin_dir }}/calicoctl create -f -
environment:
NO_DEFAULT_POOLS: true
run_once: true
when: (not legacy_calicoctl and
"Key not found" in calico_conf.stdout or "nodes" not in calico_conf.stdout)
- name: Calico (old) | Define ipip pool argument
run_once: true run_once: true
set_fact: set_fact:
ipip_arg: "--ipip" ipip_arg: "--ipip"
when: cloud_provider is defined or ipip|default(false) when: (legacy_calicoctl and
cloud_provider is defined or ipip)
- name: Calico | Define nat-outgoing pool argument - name: Calico (old) | Define nat-outgoing pool argument
run_once: true run_once: true
set_fact: set_fact:
nat_arg: "--nat-outgoing" nat_arg: "--nat-outgoing"
when: nat_outgoing|default(false) and not peer_with_router|default(false) when: (legacy_calicoctl and
nat_outgoing|default(false) and not peer_with_router|default(false))
- name: Calico | Define calico pool task name - name: Calico (old) | Define calico pool task name
run_once: true run_once: true
set_fact: set_fact:
pool_task_name: "with options {{ ipip_arg|default('') }} {{ nat_arg|default('') }}" pool_task_name: "with options {{ ipip_arg|default('') }} {{ nat_arg|default('') }}"
when: ipip_arg|default(false) or nat_arg|default(false) when: (legacy_calicoctl and ipip_arg|default(false) or nat_arg|default(false))
- name: Calico | Configure calico network pool {{ pool_task_name|default('') }} - name: Calico (old) | Configure calico network pool {{ pool_task_name|default('') }}
command: "{{ bin_dir}}/calicoctl pool add {{ kube_pods_subnet }} {{ ipip_arg|default('') }} {{ nat_arg|default('') }}" command: "{{ bin_dir}}/calicoctl pool add {{ kube_pods_subnet }} {{ ipip_arg|default('') }} {{ nat_arg|default('') }}"
environment: environment:
NO_DEFAULT_POOLS: true NO_DEFAULT_POOLS: true
run_once: true run_once: true
when: calico_conf.status == 404 or "nodes" not in calico_conf.content when: (legacy_calicoctl and
"Key not found" in calico_conf.stdout or "nodes" not in calico_conf.stdout)
- name: Calico | Get calico configuration from etcd - name: Calico | Get calico configuration from etcd
uri: command: |-
url: "{{ etcd_endpoint }}/v2/keys/calico/v1/ipam/v4/pool" curl \
return_content: yes --cacert {{ etcd_cert_dir }}/ca.pem \
register: calico_pools --cert {{ etcd_cert_dir}}/admin.pem \
--key {{ etcd_cert_dir }}/admin-key.pem \
https://localhost:2379/v2/keys/calico/v1/ipam/v4/pool
register: calico_pools_raw
delegate_to: "{{groups['etcd'][0]}}"
run_once: true
- set_fact:
calico_pools: "{{ calico_pools_raw.stdout | from_json }}"
run_once: true run_once: true
- name: Calico | Check if calico pool is properly configured - name: Calico | Check if calico pool is properly configured
fail: fail:
msg: 'Only one network pool must be configured and it must be the subnet {{ kube_pods_subnet }}. msg: 'Only one network pool must be configured and it must be the subnet {{ kube_pods_subnet }}.
Please erase calico configuration and run the playbook again ("etcdctl rm --recursive /calico/v1/ipam/v4/pool")' Please erase calico configuration and run the playbook again ("etcdctl rm --recursive /calico/v1/ipam/v4/pool")'
when: ( calico_pools.json['node']['nodes'] | length > 1 ) or when: ( calico_pools['node']['nodes'] | length > 1 ) or
( not calico_pools.json['node']['nodes'][0]['key'] | search(".*{{ kube_pods_subnet | ipaddr('network') }}.*") ) ( not calico_pools['node']['nodes'][0]['key'] | search(".*{{ kube_pods_subnet | ipaddr('network') }}.*") )
run_once: true run_once: true
- name: Calico | Write /etc/network-environment - name: Calico | Write /etc/network-environment
@ -124,11 +178,30 @@
enabled: yes enabled: yes
- name: Calico | Disable node mesh - name: Calico | Disable node mesh
shell: "{{ bin_dir }}/calicoctl bgp node-mesh off" shell: "{{ bin_dir }}/calicoctl config set nodeToNodeMesh off"
when: peer_with_router|default(false) and inventory_hostname in groups['kube-node'] when: (not legacy_calicoctl and
peer_with_router|default(false) and inventory_hostname in groups['kube-node'])
- name: Calico | Configure peering with router(s) - name: Calico | Configure peering with router(s)
shell: >
echo '{
"kind": "bgppeer",
"spec": {"asNumber": {{ item.as }}},
"apiVersion": "v1",
"metadata": {"node": "rack1-host1", "scope": "node", "peerIP": "{{ item.router_id }}"}
}'
| {{ bin_dir }}/calicoctl create -f -
with_items: peers
when: (not legacy_calicoctl and
peer_with_router|default(false) and inventory_hostname in groups['kube-node'])
- name: Calico (old) | Disable node mesh
shell: "{{ bin_dir }}/calicoctl bgp node-mesh off"
when: (legacy_calicoctl and
peer_with_router|default(false) and inventory_hostname in groups['kube-node'])
- name: Calico (old) | Configure peering with router(s)
shell: "{{ bin_dir }}/calicoctl node bgp peer add {{ item.router_id }} as {{ item.as }}" shell: "{{ bin_dir }}/calicoctl node bgp peer add {{ item.router_id }} as {{ item.as }}"
with_items: peers with_items: peers
when: peer_with_router|default(false) and inventory_hostname in groups['kube-node'] when: (legacy_calicoctl and
peer_with_router|default(false) and inventory_hostname in groups['kube-node'])

View file

@ -1,17 +1,25 @@
[Unit] [Unit]
Description=Calico per-node agent Description=Calico per-node agent
Documentation=https://github.com/projectcalico/calico-docker Documentation=https://github.com/projectcalico/calico-docker
After=docker.service docker.socket etcd-proxy.service After=docker.service docker.socket
Wants=docker.socket etcd-proxy.service Wants=docker.socket
[Service] [Service]
User=root User=root
PermissionsStartOnly=true PermissionsStartOnly=true
{% if legacy_calicoctl %}
{% if inventory_hostname in groups['kube-node'] and peer_with_router|default(false)%} {% if inventory_hostname in groups['kube-node'] and peer_with_router|default(false)%}
ExecStart={{ bin_dir }}/calicoctl node --ip={{ip | default(ansible_default_ipv4.address) }} --as={{ local_as }} --detach=false --node-image={{ calico_node_image_repo }}:{{ calico_node_image_tag }} ExecStart={{ bin_dir }}/calicoctl node --ip={{ip | default(ansible_default_ipv4.address) }} --as={{ local_as }} --detach=false --node-image={{ calico_node_image_repo }}:{{ calico_node_image_tag }}
{% else %} {% else %}
ExecStart={{ bin_dir }}/calicoctl node --ip={{ip | default(ansible_default_ipv4.address) }} --detach=false --node-image={{ calico_node_image_repo }}:{{ calico_node_image_tag }} ExecStart={{ bin_dir }}/calicoctl node --ip={{ip | default(ansible_default_ipv4.address) }} --detach=false --node-image={{ calico_node_image_repo }}:{{ calico_node_image_tag }}
{% endif %} {% endif %}
{% else %}
{% if inventory_hostname in groups['kube-node'] and peer_with_router|default(false)%}
ExecStart={{ bin_dir }}/calicoctl node run --ip={{ip | default(ansible_default_ipv4.address) }} --as={{ local_as }} --node-image={{ calico_node_image_repo }}:{{ calico_node_image_tag }}
{% else %}
ExecStart={{ bin_dir }}/calicoctl node run --ip={{ip | default(ansible_default_ipv4.address) }} --node-image={{ calico_node_image_repo }}:{{ calico_node_image_tag }}
{% endif %}
{% endif %}
Restart=always Restart=always
RestartSec=10s RestartSec=10s

View file

@ -1,8 +1,13 @@
#!/bin/bash #!/bin/bash
/usr/bin/docker run --privileged --rm \ /usr/bin/docker run -i --privileged --rm \
--net=host --pid=host -e ETCD_AUTHORITY={{ etcd_authority }} \ --net=host --pid=host \
-e ETCD_ENDPOINTS={{ etcd_access_endpoint }} \
-e ETCD_CA_CERT_FILE=/etc/calico/certs/ca_cert.crt \
-e ETCD_CERT_FILE=/etc/calico/certs/cert.crt \
-e ETCD_KEY_FILE=/etc/calico/certs/key.pem \
-v /usr/bin/docker:/usr/bin/docker \ -v /usr/bin/docker:/usr/bin/docker \
-v /var/run/docker.sock:/var/run/docker.sock \ -v /var/run/docker.sock:/var/run/docker.sock \
-v /var/run/calico:/var/run/calico \ -v /var/run/calico:/var/run/calico \
-v /etc/calico/certs:/etc/calico/certs:ro \
{{ calicoctl_image_repo }}:{{ calicoctl_image_tag}} \ {{ calicoctl_image_repo }}:{{ calicoctl_image_tag}} \
$@ $@

View file

@ -37,7 +37,7 @@ DAEMON_USER=root
do_status() do_status()
{ {
if [ $($DOCKER ps | awk '{ print $2 }' | grep calico/node | wc -l) -eq 1 ]; then if [ $($DOCKER ps --format "{{.Image}}" | grep -cw 'calico/node') -eq 1 ]; then
return 0 return 0
else else
return 1 return 1
@ -51,7 +51,11 @@ do_start()
do_status do_status
retval=$? retval=$?
if [ $retval -ne 0 ]; then if [ $retval -ne 0 ]; then
{% if legacy_calicoctl %}
${DAEMON} node --ip=${DEFAULT_IPV4} >>/dev/null && return 0 || return 2 ${DAEMON} node --ip=${DEFAULT_IPV4} >>/dev/null && return 0 || return 2
{% else %}
${DAEMON} node run --ip=${DEFAULT_IPV4} >>/dev/null && return 0 || return 2
{% endif %}
else else
return 1 return 1
fi fi
@ -62,7 +66,12 @@ do_start()
# #
do_stop() do_stop()
{ {
{% if legacy_calicoctl %}
${DAEMON} node stop >> /dev/null || ${DAEMON} node stop --force >> /dev/null ${DAEMON} node stop >> /dev/null || ${DAEMON} node stop --force >> /dev/null
{% else %}
echo "Current version of ${DAEMON} doesn't support 'node stop' command!"
return 1
{% endif %}
} }

View file

@ -3,7 +3,10 @@
DEFAULT_IPV4={{ip | default(ansible_default_ipv4.address) }} DEFAULT_IPV4={{ip | default(ansible_default_ipv4.address) }}
# The Kubernetes master IP # The Kubernetes master IP
KUBERNETES_MASTER={{ first_kube_master }} KUBERNETES_MASTER={{ kube_apiserver_endpoint }}
# IP and port of etcd instance used by Calico # IP and port of etcd instance used by Calico
ETCD_AUTHORITY={{ etcd_authority }} ETCD_ENDPOINTS={{ etcd_access_endpoint }}
ETCD_CA_CERT_FILE=/etc/calico/certs/ca_cert.crt
ETCD_CERT_FILE=/etc/calico/certs/cert.crt
ETCD_KEY_FILE=/etc/calico/certs/key.pem

View file

@ -31,7 +31,7 @@ logfile="/var/log/$prog"
do_status() do_status()
{ {
if [ $($dockerexec ps | awk '{ print $2 }' | grep calico/node | wc -l) -ne 1 ]; then if [ $($dockerexec ps --format "{{.Image}}" | grep -cw 'calico/node') -ne 1 ]; then
return 1 return 1
fi fi
} }
@ -53,7 +53,11 @@ do_start() {
if [ $retval -ne 0 ]; then if [ $retval -ne 0 ]; then
printf "Starting $prog:\t" printf "Starting $prog:\t"
echo "\n$(date)\n" >> $logfile echo "\n$(date)\n" >> $logfile
{% if legacy_calicoctl %}
$exec node --ip=${DEFAULT_IPV4} &>>$logfile $exec node --ip=${DEFAULT_IPV4} &>>$logfile
{% else %}
$exec node run --ip=${DEFAULT_IPV4} &>>$logfile
{% endif %}
success success
echo echo
else else
@ -65,7 +69,12 @@ do_start() {
do_stop() { do_stop() {
echo -n $"Stopping $prog: " echo -n $"Stopping $prog: "
{% if legacy_calicoctl %}
$exec node stop >> /dev/null || $exec node stop --force >> /dev/null $exec node stop >> /dev/null || $exec node stop --force >> /dev/null
{% else %}
echo "Current version of ${exec} doesn't support 'node stop' command!"
return 1
{% endif %}
retval=$? retval=$?
echo echo
return $retval return $retval

View file

@ -0,0 +1,11 @@
# The interface used by canal for host <-> host communication.
# If left blank, then the interface is chosing using the node's
# default route.
canal_iface: ""
# Whether or not to masquerade traffic to destinations not within
# the pod network.
canal_masquerade: "true"
# Log-level
canal_log_level: "info"

View file

@ -0,0 +1,12 @@
---
dependencies:
- role: download
file: "{{ downloads.flannel_server_helper }}"
- role: download
file: "{{ downloads.flannel }}"
- role: download
file: "{{ downloads.calico_node }}"
- role: download
file: "{{ downloads.calicoctl }}"
- role: download
file: "{{ downloads.calico_cni }}"

View file

@ -0,0 +1,34 @@
---
- name: Canal | Set Flannel etcd configuration
command: |-
{{ bin_dir }}/etcdctl --peers={{ etcd_access_addresses }} \
set /{{ cluster_name }}/network/config \
'{ "Network": "{{ kube_pods_subnet }}", "SubnetLen": {{ kube_network_node_prefix }}, "Backend": { "Type": "{{ flannel_backend_type }}" } }'
delegate_to: "{{groups['etcd'][0]}}"
run_once: true
- name: Canal | Write canal configmap
template:
src: canal-config.yml.j2
dest: /etc/kubernetes/canal-config.yaml
- name: Canal | Write canal node configuration
template:
src: canal-node.yml.j2
dest: /etc/kubernetes/canal-node.yaml
- name: Canal | Copy cni plugins from hyperkube
command: "/usr/bin/docker run --rm -v /opt/cni/bin:/cnibindir {{ hyperkube_image_repo }}:{{ hyperkube_image_tag }} /usr/bin/rsync -a /opt/cni/bin/ /cnibindir/"
register: cni_task_result
until: cni_task_result.rc == 0
retries: 4
delay: "{{ retry_stagger | random + 3 }}"
changed_when: false
- name: Canal | Copy cni plugins from calico/cni
command: "/usr/bin/docker run --rm -v /opt/cni/bin:/cnibindir {{ calico_cni_image_repo }}:{{ calico_cni_image_tag }} sh -c 'cp -a /opt/cni/bin/* /cnibindir/'"
register: cni_task_result
until: cni_task_result.rc == 0
retries: 4
delay: "{{ retry_stagger | random + 3 }}"
changed_when: false

View file

@ -0,0 +1,22 @@
# This ConfigMap can be used to configure a self-hosted Canal installation.
# See `canal.yaml` for an example of a Canal deployment which uses
# the config in this ConfigMap.
kind: ConfigMap
apiVersion: v1
metadata:
name: canal-config
data:
# Configure this with the location of your etcd cluster.
etcd_endpoints: "{{ etcd_access_endpoint }}"
# The interface used by canal for host <-> host communication.
# If left blank, then the interface is chosing using the node's
# default route.
flanneld_iface: "{{ canal_iface }}"
# Whether or not to masquerade traffic to destinations not within
# the pod network.
masquerade: "{{ canal_masquerade }}"
# Cluster name for Flannel etcd path
cluster_name: "{{ cluster_name }}"

View file

@ -0,0 +1,119 @@
---
kind: DaemonSet
apiVersion: extensions/v1beta1
metadata:
name: canal-node
labels:
k8s-app: canal-node
spec:
selector:
matchLabels:
k8s-app: canal-node
template:
metadata:
annotations:
scheduler.alpha.kubernetes.io/critical-pod: ''
scheduler.alpha.kubernetes.io/tolerations: '[{"key":"CriticalAddonsOnly", "operator":"Exists"}]'
labels:
k8s-app: canal-node
spec:
hostNetwork: true
volumes:
# Used by calico/node.
- name: lib-modules
hostPath:
path: /lib/modules
- name: var-run-calico
hostPath:
path: /var/run/calico
# Used to install CNI.
- name: cni-bin-dir
hostPath:
path: /opt/cni/bin
- name: cni-net-dir
hostPath:
path: /etc/cni/net.d
# Used by flannel daemon.
- name: run-flannel
hostPath:
path: /run/flannel
- name: resolv
hostPath:
path: /etc/resolv.conf
containers:
# Runs the flannel daemon to enable vxlan networking between
# container hosts.
- name: flannel
image: "{{ flannel_image_repo }}:{{ flannel_image_tag }}"
env:
# Cluster name
- name: CLUSTER_NAME
valueFrom:
configMapKeyRef:
name: canal-config
key: cluster_name
# The location of the etcd cluster.
- name: FLANNELD_ETCD_ENDPOINTS
valueFrom:
configMapKeyRef:
name: canal-config
key: etcd_endpoints
# The interface flannel should run on.
- name: FLANNELD_IFACE
valueFrom:
configMapKeyRef:
name: canal-config
key: flanneld_iface
# Perform masquerade on traffic leaving the pod cidr.
- name: FLANNELD_IP_MASQ
valueFrom:
configMapKeyRef:
name: canal-config
key: masquerade
# Set etcd-prefix
- name: DOCKER_OPT_ETCD_PREFIX
value: "-etcd-prefix=/$(CLUSTER_NAME)/network"
# Write the subnet.env file to the mounted directory.
- name: FLANNELD_SUBNET_FILE
value: "/run/flannel/subnet.env"
command:
- "/bin/sh"
- "-c"
- "/opt/bin/flanneld -etcd-prefix /$(CLUSTER_NAME)/network"
ports:
- hostPort: 10253
containerPort: 10253
securityContext:
privileged: true
volumeMounts:
- name: "resolv"
mountPath: "/etc/resolv.conf"
- name: "run-flannel"
mountPath: "/run/flannel"
# Runs calico/node container on each Kubernetes node. This
# container programs network policy and local routes on each
# host.
- name: calico-node
image: "{{ calico_node_image_repo }}:{{ calico_node_image_tag }}"
env:
# The location of the etcd cluster.
- name: ETCD_ENDPOINTS
valueFrom:
configMapKeyRef:
name: canal-config
key: etcd_endpoints
# Disable Calico BGP. Calico is simply enforcing policy.
- name: CALICO_NETWORKING
value: "false"
# Disable file logging so `kubectl logs` works.
- name: CALICO_DISABLE_FILE_LOGGING
value: "true"
securityContext:
privileged: true
volumeMounts:
- mountPath: /lib/modules
name: lib-modules
readOnly: true
- mountPath: /var/run/calico
name: var-run-calico
readOnly: false

View file

@ -1,9 +1,11 @@
--- ---
- name: Flannel | Write flannel configuration - name: Flannel | Set Flannel etcd configuration
template: command: |-
src: network.json {{ bin_dir }}/etcdctl --peers={{ etcd_access_addresses }} \
dest: /etc/flannel-network.json set /{{ cluster_name }}/network/config \
backup: yes '{ "Network": "{{ kube_pods_subnet }}", "SubnetLen": {{ kube_network_node_prefix }}, "Backend": { "Type": "{{ flannel_backend_type }}" } }'
delegate_to: "{{groups['etcd'][0]}}"
run_once: true
- name: Flannel | Create flannel pod manifest - name: Flannel | Create flannel pod manifest
template: template:

View file

@ -12,26 +12,16 @@
- name: "subnetenv" - name: "subnetenv"
hostPath: hostPath:
path: "/run/flannel" path: "/run/flannel"
- name: "networkconfig" - name: "etcd-certs"
hostPath: hostPath:
path: "/etc/flannel-network.json" path: "{{ etcd_cert_dir }}"
containers: containers:
- name: "flannel-server-helper"
image: "{{ flannel_server_helper_image_repo }}:{{ flannel_server_helper_image_tag }}"
args:
- "--network-config=/etc/flannel-network.json"
- "--etcd-prefix=/{{ cluster_name }}/network"
- "--etcd-server={{ etcd_endpoint }}"
volumeMounts:
- name: "networkconfig"
mountPath: "/etc/flannel-network.json"
imagePullPolicy: "Always"
- name: "flannel-container" - name: "flannel-container"
image: "{{ flannel_image_repo }}:{{ flannel_image_tag }}" image: "{{ flannel_image_repo }}:{{ flannel_image_tag }}"
command: command:
- "/bin/sh" - "/bin/sh"
- "-c" - "-c"
- "/opt/bin/flanneld -etcd-endpoints {{ etcd_access_endpoint }} -etcd-prefix /{{ cluster_name }}/network {% if flannel_interface is defined %}-iface {{ flannel_interface }}{% endif %} {% if flannel_public_ip is defined %}-public-ip {{ flannel_public_ip }}{% endif %}" - "/opt/bin/flanneld -etcd-endpoints {{ etcd_access_endpoint }} -etcd-prefix /{{ cluster_name }}/network -etcd-cafile {{ etcd_cert_dir }}/ca.pem -etcd-certfile {{ etcd_cert_dir }}/node.pem -etcd-keyfile {{ etcd_cert_dir }}/node-key.pem {% if flannel_interface is defined %}-iface {{ flannel_interface }}{% endif %} {% if flannel_public_ip is defined %}-public-ip {{ flannel_public_ip }}{% endif %}"
ports: ports:
- hostPort: 10253 - hostPort: 10253
containerPort: 10253 containerPort: 10253
@ -41,6 +31,8 @@
volumeMounts: volumeMounts:
- name: "subnetenv" - name: "subnetenv"
mountPath: "/run/flannel" mountPath: "/run/flannel"
- name: "etcd-certs"
mountPath: "{{ etcd_cert_dir }}"
securityContext: securityContext:
privileged: true privileged: true
hostNetwork: true hostNetwork: true

View file

@ -1 +0,0 @@
{ "Network": "{{ kube_pods_subnet }}", "SubnetLen": {{ kube_network_node_prefix }}, "Backend": { "Type": "{{ flannel_backend_type }}" } }

View file

@ -6,3 +6,5 @@ dependencies:
when: kube_network_plugin == 'flannel' when: kube_network_plugin == 'flannel'
- role: network_plugin/weave - role: network_plugin/weave
when: kube_network_plugin == 'weave' when: kube_network_plugin == 'weave'
- role: network_plugin/canal
when: kube_network_plugin == 'canal'

View file

@ -2,10 +2,10 @@
local_release_dir: /tmp local_release_dir: /tmp
# Versions # Versions
kube_version: v1.4.0 kube_version: v1.4.3
etcd_version: v3.0.6 etcd_version: v3.0.6
calico_version: v0.22.0 calico_version: v0.23.0
calico_cni_version: v1.4.2 calico_cni_version: v1.4.2
weave_version: v1.6.1 weave_version: v1.6.1

View file

@ -1,21 +1,14 @@
--- ---
- hosts: all - hosts: all
become: true become: false
gather_facts: no gather_facts: no
vars: vars:
debug: false
commands: commands:
- name: git_info
cmd: find . -type d -name .git -execdir sh -c 'gen-gitinfos.sh global|head -12' \;
- name: timedate_info - name: timedate_info
cmd: timedatectl status cmd: timedatectl status
- name: space_info
cmd: df -h
- name: kernel_info - name: kernel_info
cmd: uname -r cmd: uname -r
- name: distro_info
cmd: cat /etc/issue.net
- name: docker_info - name: docker_info
cmd: docker info cmd: docker info
- name: ip_info - name: ip_info
@ -24,23 +17,66 @@
cmd: ip ro cmd: ip ro
- name: proc_info - name: proc_info
cmd: ps auxf | grep -v ]$ cmd: ps auxf | grep -v ]$
- name: systemctl_info
cmd: systemctl status
- name: systemctl_failed_info - name: systemctl_failed_info
cmd: systemctl --state=failed --no-pager cmd: systemctl --state=failed --no-pager
- name: k8s_info - name: k8s_info
cmd: kubectl get all --all-namespaces -o wide cmd: kubectl get all --all-namespaces -o wide
- name: errors_info - name: errors_info
cmd: journalctl -p err --utc --no-pager cmd: journalctl -p err --utc --no-pager
- name: etcd_info
cmd: etcdctl --debug cluster-health
- name: weave_info
cmd: weave report | jq "."
- name: weave_logs
cmd: docker logs weave > weave.log
- name: kubedns_logs
cmd: sh -c "for i in `kubectl get pods --all-namespaces -l k8s-app=kubedns -o name`;
do kubectl logs $i --namespace kube-system kubedns > kubedns.log; done"
- name: apiserver_logs
cmd: sh -c "for i in `kubectl get pods --all-namespaces -l k8s-app=kube-apiserver -o name`;
do kubectl logs $i --namespace kube-system > kube-apiserver.log; done"
- name: controller_logs
cmd: sh -c "for i in `kubectl get pods --all-namespaces -l k8s-app=kube-controller -o name`;
do kubectl logs $i --namespace kube-system > kube-controller.log; done"
- name: scheduler_logs
cmd: sh -c "for i in `kubectl get pods --all-namespaces -l k8s-app=kube-scheduler -o name`;
do kubectl logs $i --namespace kube-system > kube-scheduler.log; done"
- name: proxy_logs
cmd: sh -c "for i in `kubectl get pods --all-namespaces -l k8s-app=kube-proxy -o name`;
do kubectl logs $i --namespace kube-system > kube-proxy.log; done"
- name: nginx_logs
cmd: sh -c "for i in `kubectl get pods --all-namespaces -l k8s-app=kube-nginx -o name`;
do kubectl logs $i --namespace kube-system > kube-nginx.log; done"
- name: flannel_logs
cmd: sh -c "for i in `kubectl get pods --all-namespaces -l app=flannel -o name`;
do kubectl logs $i --namespace kube-system flannel-container > flannel.log; done"
- name: canal_logs
cmd: sh -c "for i in `kubectl get pods --all-namespaces -l k8s-app=canal-node -o name`;
do kubectl logs $i --namespace kube-system flannel > flannel.log; done"
- name: calico_policy_logs
cmd: sh -c "for i in `kubectl get pods --all-namespaces -l k8s-app=calico-policy -o name`;
do kubectl logs $i --namespace kube-system calico-policy-controller > calico-policy-controller.log; done"
logs: logs:
- /var/log/ansible.log
- /var/log/ansible/ansible.log
- /var/log/syslog - /var/log/syslog
- /var/log/daemon.log - /var/log/daemon.log
- /var/log/kern.log - /var/log/kern.log
- inventory/inventory.ini - /var/log/dpkg.log
- cluster.yml - /var/log/apt/history.log
- /var/log/yum.log
- /var/log/calico/bird/current
- /var/log/calico/bird6/current
- /var/log/calico/felix/current
- /var/log/calico/confd/current
- weave.log
- kubedns.log
- kube-apiserver.log
- kube-controller.log
- kube-scheduler.log
- kube-proxy.log
- kube-nginx.log
- flannel.log
- calico-policy-controller.log
tasks: tasks:
- name: Storing commands output - name: Storing commands output
@ -48,10 +84,7 @@
register: output register: output
ignore_errors: true ignore_errors: true
with_items: "{{commands}}" with_items: "{{commands}}"
no_log: True
- debug: var=item
with_items: output.results
when: debug
- name: Fetch results - name: Fetch results
fetch: src={{ item.name }} dest=/tmp/collect-info/commands fetch: src={{ item.name }} dest=/tmp/collect-info/commands
@ -62,7 +95,7 @@
with_items: "{{logs}}" with_items: "{{logs}}"
- name: Pack results and logs - name: Pack results and logs
local_action: shell GZIP=-9 tar --remove-files -cvzf logs.tar.gz -C /tmp collect-info local_action: shell GZIP=-9 tar --remove-files -cvzf {{dir|default(".")}}/logs.tar.gz -C /tmp collect-info
run_once: true run_once: true
- name: Clean up collected command outputs - name: Clean up collected command outputs

View file

@ -1,39 +0,0 @@
---
- hosts: localhost
become: true
gather_facts: no
vars:
log_path: /var/log/ansible/
conf_file: /etc/ansible/ansible.cfg
human_readable_plugin: false
callback_plugin_path: /usr/share/ansible/plugins/callback
tasks:
- name: LOGS | ensure log path
file: path="{{log_path}}" state=directory owner={{ansible_ssh_user}}
- name: LOGS | ensure plugin path
file: path="{{callback_plugin_path}}" state=directory owner={{ansible_ssh_user}}
when: human_readable_plugin
- name: LOGS | get plugin
git: repo=https://gist.github.com/cd706de198c85a8255f6.git dest=/tmp/cd706de198c85a8255f6
when: human_readable_plugin
- name: LOGS | install plugin
copy: src=/tmp/cd706de198c85a8255f6/human_log.py dest="{{callback_plugin_path}}"
when: human_readable_plugin
- name: LOGS | config
lineinfile:
line: "log_path={{log_path}}/ansible.log"
regexp: "^#log_path|^log_path"
dest: "{{conf_file}}"
- name: LOGS | callback plugin
lineinfile:
line: "callback_plugins={{callback_plugin_path}}"
regexp: "^#callback_plugins|^callback_plugins"
dest: "{{conf_file}}"
when: human_readable_plugin

View file

@ -2,3 +2,6 @@
pipelining=True pipelining=True
[defaults] [defaults]
host_key_checking=False host_key_checking=False
gathering = smart
fact_caching = jsonfile
fact_caching_connection = /tmp

View file

@ -1,6 +1,6 @@
--- ---
- hosts: localhost - hosts: localhost
sudo: False become: false
gather_facts: no gather_facts: no
vars: vars:
cloud_machine_type: g1-small cloud_machine_type: g1-small

View file

@ -1,6 +1,6 @@
--- ---
- hosts: localhost - hosts: localhost
sudo: False become: false
gather_facts: no gather_facts: no
vars: vars:
cloud_machine_type: f1-micro cloud_machine_type: f1-micro

View file

@ -0,0 +1,11 @@
[Credentials]
gs_access_key_id = {{ gs_key }}
gs_secret_access_key = {{ gs_skey }}
[Boto]
https_validate_certificates = True
[GoogleCompute]
[GSUtil]
default_project_id = {{ gce_project_id }}
content_language = en
default_api_version = 2
[OAuth2]

View file

@ -0,0 +1,9 @@
{
"rule":
[
{
"action": {"type": "Delete"},
"condition": {"age": {{expire_days}}}
}
]
}

View file

@ -0,0 +1,75 @@
---
- hosts: localhost
become: false
gather_facts: no
vars:
expire_days: 2
tasks:
- name: Generate uniq bucket name prefix
shell: date +%Y%m%d
register: out
- name: replace_test_id
set_fact:
test_name: "kargo-ci-{{ out.stdout }}"
- set_fact:
file_name: "{{ostype}}-{{kube_network_plugin}}-{{commit}}-logs.tar.gz"
- name: Create a bucket
gc_storage:
bucket: "{{ test_name }}"
mode: create
permission: public-read
gs_access_key: "{{ gs_key }}"
gs_secret_key: "{{ gs_skey }}"
no_log: True
- name: Create a lifecycle template for the bucket
template:
src: gcs_life.json.j2
dest: "{{dir}}/gcs_life.json"
- name: Create a boto config to access GCS
template:
src: boto.j2
dest: "{{dir}}/.boto"
no_log: True
- name: Download gsutil cp installer
get_url:
url: https://dl.google.com/dl/cloudsdk/channels/rapid/install_google_cloud_sdk.bash
dest: "{{dir}}/gcp-installer.sh"
- name: Get gsutil tool
script: "{{dir}}/gcp-installer.sh"
environment:
CLOUDSDK_CORE_DISABLE_PROMPTS: 1
CLOUDSDK_INSTALL_DIR: "{{dir}}"
no_log: True
ignore_errors: true
- name: Apply the lifecycle rules
command: "{{dir}}/google-cloud-sdk/bin/gsutil lifecycle set {{dir}}/gcs_life.json gs://{{test_name}}"
environment:
BOTO_CONFIG: "{{dir}}/.boto"
no_log: True
- name: Upload collected diagnostic info
gc_storage:
bucket: "{{ test_name }}"
mode: put
permission: public-read
object: "{{ file_name }}"
src: "{{dir}}/logs.tar.gz"
headers: '{"Content-Encoding": "x-gzip"}'
gs_access_key: "{{ gs_key }}"
gs_secret_key: "{{ gs_skey }}"
expiration: "{{expire_days * 36000|int}}"
ignore_errors: true
no_log: True
- debug:
msg: "A public url https://storage.googleapis.com/{{test_name}}/{{file_name}}"

View file

@ -2,6 +2,16 @@ node1 ansible_ssh_host={{gce.instance_data[0].public_ip}}
node2 ansible_ssh_host={{gce.instance_data[1].public_ip}} node2 ansible_ssh_host={{gce.instance_data[1].public_ip}}
node3 ansible_ssh_host={{gce.instance_data[2].public_ip}} node3 ansible_ssh_host={{gce.instance_data[2].public_ip}}
{% if mode is defined and mode == "separate" %}
[kube-master]
node1
[kube-node]
node2
[etcd]
node3
{% else %}
[kube-master] [kube-master]
node1 node1
node2 node2
@ -14,6 +24,7 @@ node3
[etcd] [etcd]
node1 node1
node2 node2
{% endif %}
[k8s-cluster:children] [k8s-cluster:children]
kube-node kube-node