5 changed files with 455 additions and 28 deletions
Unified View
Diff Options
-
4roles/kubernetes-apps/defaults/main.yaml
-
318roles/kubernetes-apps/library/kube.py
-
42roles/kubernetes-apps/tasks/main.yaml
-
99roles/kubernetes-apps/templates/kubedns-rc.yml
-
20roles/kubernetes-apps/templates/kubedns-svc.yml
@ -1,4 +0,0 @@ |
|||||
--- |
|
||||
kpm_registry: "https://api.kpm.sh" |
|
||||
kpm_namespace: "default" |
|
||||
kpm_packages: [] |
|
@ -0,0 +1,318 @@ |
|||||
|
#!/usr/bin/python |
||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
DOCUMENTATION = """ |
||||
|
--- |
||||
|
module: kube |
||||
|
short_description: Manage Kubernetes Cluster |
||||
|
description: |
||||
|
- Create, replace, remove, and stop resources within a Kubernetes Cluster |
||||
|
version_added: "2.0" |
||||
|
options: |
||||
|
name: |
||||
|
required: false |
||||
|
default: null |
||||
|
description: |
||||
|
- The name associated with resource |
||||
|
filename: |
||||
|
required: false |
||||
|
default: null |
||||
|
description: |
||||
|
- The path and filename of the resource(s) definition file. |
||||
|
kubectl: |
||||
|
required: false |
||||
|
default: null |
||||
|
description: |
||||
|
- The path to the kubectl bin |
||||
|
namespace: |
||||
|
required: false |
||||
|
default: null |
||||
|
description: |
||||
|
- The namespace associated with the resource(s) |
||||
|
resource: |
||||
|
required: false |
||||
|
default: null |
||||
|
description: |
||||
|
- The resource to perform an action on. pods (po), replicationControllers (rc), services (svc) |
||||
|
label: |
||||
|
required: false |
||||
|
default: null |
||||
|
description: |
||||
|
- The labels used to filter specific resources. |
||||
|
server: |
||||
|
required: false |
||||
|
default: null |
||||
|
description: |
||||
|
- The url for the API server that commands are executed against. |
||||
|
api_version: |
||||
|
required: false |
||||
|
choices: ['v1', 'v1beta3'] |
||||
|
default: v1 |
||||
|
description: |
||||
|
- The API version associated with cluster. |
||||
|
force: |
||||
|
required: false |
||||
|
default: false |
||||
|
description: |
||||
|
- A flag to indicate to force delete, replace, or stop. |
||||
|
all: |
||||
|
required: false |
||||
|
default: false |
||||
|
description: |
||||
|
- A flag to indicate delete all, stop all, or all namespaces when checking exists. |
||||
|
log_level: |
||||
|
required: false |
||||
|
default: 0 |
||||
|
description: |
||||
|
- Indicates the level of verbosity of logging by kubectl. |
||||
|
state: |
||||
|
required: false |
||||
|
choices: ['present', 'absent', 'latest', 'reloaded', 'stopped'] |
||||
|
default: present |
||||
|
description: |
||||
|
- present handles checking existence or creating if definition file provided, |
||||
|
absent handles deleting resource(s) based on other options, |
||||
|
latest handles creating ore updating based on existence, |
||||
|
reloaded handles updating resource(s) definition using definition file, |
||||
|
stopped handles stopping resource(s) based on other options. |
||||
|
requirements: |
||||
|
- kubectl |
||||
|
author: "Kenny Jones (@kenjones-cisco)" |
||||
|
""" |
||||
|
|
||||
|
EXAMPLES = """ |
||||
|
- name: test nginx is present |
||||
|
kube: name=nginx resource=rc state=present |
||||
|
|
||||
|
- name: test nginx is stopped |
||||
|
kube: name=nginx resource=rc state=stopped |
||||
|
|
||||
|
- name: test nginx is absent |
||||
|
kube: name=nginx resource=rc state=absent |
||||
|
|
||||
|
- name: test nginx is present |
||||
|
kube: filename=/tmp/nginx.yml |
||||
|
""" |
||||
|
|
||||
|
|
||||
|
class KubeManager(object): |
||||
|
|
||||
|
def __init__(self, module): |
||||
|
|
||||
|
self.module = module |
||||
|
|
||||
|
self.kubectl = module.params.get('kubectl') |
||||
|
if self.kubectl is None: |
||||
|
self.kubectl = module.get_bin_path('kubectl', True) |
||||
|
self.base_cmd = [self.kubectl] |
||||
|
self.api_version = module.params.get('api_version') |
||||
|
|
||||
|
if self.api_version: |
||||
|
self.base_cmd.append('--api-version=' + self.api_version) |
||||
|
|
||||
|
if module.params.get('server'): |
||||
|
self.base_cmd.append('--server=' + module.params.get('server')) |
||||
|
|
||||
|
if module.params.get('log_level'): |
||||
|
self.base_cmd.append('--v=' + str(module.params.get('log_level'))) |
||||
|
|
||||
|
if module.params.get('namespace'): |
||||
|
self.base_cmd.append('--namespace=' + module.params.get('namespace')) |
||||
|
|
||||
|
self.all = module.params.get('all') |
||||
|
self.force = module.params.get('force') |
||||
|
self.name = module.params.get('name') |
||||
|
self.filename = module.params.get('filename') |
||||
|
self.resource = module.params.get('resource') |
||||
|
self.label = module.params.get('label') |
||||
|
|
||||
|
def _execute(self, cmd): |
||||
|
args = self.base_cmd + cmd |
||||
|
try: |
||||
|
rc, out, err = self.module.run_command(args) |
||||
|
if rc != 0: |
||||
|
self.module.fail_json( |
||||
|
msg='error running kubectl (%s) command (rc=%d): %s' % (' '.join(args), rc, out or err)) |
||||
|
except Exception as exc: |
||||
|
self.module.fail_json( |
||||
|
msg='error running kubectl (%s) command: %s' % (' '.join(args), str(exc))) |
||||
|
return out.splitlines() |
||||
|
|
||||
|
def _execute_nofail(self, cmd): |
||||
|
args = self.base_cmd + cmd |
||||
|
rc, out, err = self.module.run_command(args) |
||||
|
if rc != 0: |
||||
|
return None |
||||
|
return out.splitlines() |
||||
|
|
||||
|
def create(self, check=True): |
||||
|
if check and self.exists(): |
||||
|
return [] |
||||
|
|
||||
|
cmd = ['create'] |
||||
|
|
||||
|
if not self.filename: |
||||
|
self.module.fail_json(msg='filename required to create') |
||||
|
|
||||
|
cmd.append('--filename=' + self.filename) |
||||
|
|
||||
|
return self._execute(cmd) |
||||
|
|
||||
|
def replace(self): |
||||
|
|
||||
|
if not self.force and not self.exists(): |
||||
|
return [] |
||||
|
|
||||
|
cmd = ['replace'] |
||||
|
if self.api_version != 'v1': |
||||
|
cmd = ['update'] |
||||
|
|
||||
|
if self.force: |
||||
|
cmd.append('--force') |
||||
|
|
||||
|
if not self.filename: |
||||
|
self.module.fail_json(msg='filename required to reload') |
||||
|
|
||||
|
cmd.append('--filename=' + self.filename) |
||||
|
|
||||
|
return self._execute(cmd) |
||||
|
|
||||
|
def delete(self): |
||||
|
|
||||
|
if not self.force and not self.exists(): |
||||
|
return [] |
||||
|
|
||||
|
cmd = ['delete'] |
||||
|
|
||||
|
if self.filename: |
||||
|
cmd.append('--filename=' + self.filename) |
||||
|
else: |
||||
|
if not self.resource: |
||||
|
self.module.fail_json(msg='resource required to delete without filename') |
||||
|
|
||||
|
cmd.append(self.resource) |
||||
|
|
||||
|
if self.name: |
||||
|
cmd.append(self.name) |
||||
|
|
||||
|
if self.label: |
||||
|
cmd.append('--selector=' + self.label) |
||||
|
|
||||
|
if self.all: |
||||
|
cmd.append('--all') |
||||
|
|
||||
|
if self.force: |
||||
|
cmd.append('--ignore-not-found') |
||||
|
|
||||
|
return self._execute(cmd) |
||||
|
|
||||
|
def exists(self): |
||||
|
cmd = ['get'] |
||||
|
|
||||
|
if not self.resource: |
||||
|
return False |
||||
|
|
||||
|
cmd.append(self.resource) |
||||
|
|
||||
|
if self.name: |
||||
|
cmd.append(self.name) |
||||
|
|
||||
|
cmd.append('--no-headers') |
||||
|
|
||||
|
if self.label: |
||||
|
cmd.append('--selector=' + self.label) |
||||
|
|
||||
|
if self.all: |
||||
|
cmd.append('--all-namespaces') |
||||
|
|
||||
|
result = self._execute_nofail(cmd) |
||||
|
if not result: |
||||
|
return False |
||||
|
return True |
||||
|
|
||||
|
def stop(self): |
||||
|
|
||||
|
if not self.force and not self.exists(): |
||||
|
return [] |
||||
|
|
||||
|
cmd = ['stop'] |
||||
|
|
||||
|
if self.filename: |
||||
|
cmd.append('--filename=' + self.filename) |
||||
|
else: |
||||
|
if not self.resource: |
||||
|
self.module.fail_json(msg='resource required to stop without filename') |
||||
|
|
||||
|
cmd.append(self.resource) |
||||
|
|
||||
|
if self.name: |
||||
|
cmd.append(self.name) |
||||
|
|
||||
|
if self.label: |
||||
|
cmd.append('--selector=' + self.label) |
||||
|
|
||||
|
if self.all: |
||||
|
cmd.append('--all') |
||||
|
|
||||
|
if self.force: |
||||
|
cmd.append('--ignore-not-found') |
||||
|
|
||||
|
return self._execute(cmd) |
||||
|
|
||||
|
|
||||
|
def main(): |
||||
|
|
||||
|
module = AnsibleModule( |
||||
|
argument_spec=dict( |
||||
|
name=dict(), |
||||
|
filename=dict(), |
||||
|
namespace=dict(), |
||||
|
resource=dict(), |
||||
|
label=dict(), |
||||
|
server=dict(), |
||||
|
kubectl=dict(), |
||||
|
api_version=dict(default='v1', choices=['v1', 'v1beta3']), |
||||
|
force=dict(default=False, type='bool'), |
||||
|
all=dict(default=False, type='bool'), |
||||
|
log_level=dict(default=0, type='int'), |
||||
|
state=dict(default='present', choices=['present', 'absent', 'latest', 'reloaded', 'stopped']), |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
changed = False |
||||
|
|
||||
|
manager = KubeManager(module) |
||||
|
state = module.params.get('state') |
||||
|
|
||||
|
if state == 'present': |
||||
|
result = manager.create() |
||||
|
|
||||
|
elif state == 'absent': |
||||
|
result = manager.delete() |
||||
|
|
||||
|
elif state == 'reloaded': |
||||
|
result = manager.replace() |
||||
|
|
||||
|
elif state == 'stopped': |
||||
|
result = manager.stop() |
||||
|
|
||||
|
elif state == 'latest': |
||||
|
if manager.exists(): |
||||
|
manager.force = True |
||||
|
result = manager.replace() |
||||
|
else: |
||||
|
result = manager.create(check=False) |
||||
|
|
||||
|
else: |
||||
|
module.fail_json(msg='Unrecognized state %s.' % state) |
||||
|
|
||||
|
if result: |
||||
|
changed = True |
||||
|
module.exit_json(changed=changed, |
||||
|
msg='success: %s' % (' '.join(result)) |
||||
|
) |
||||
|
|
||||
|
|
||||
|
from ansible.module_utils.basic import * # noqa |
||||
|
if __name__ == '__main__': |
||||
|
main() |
@ -1,25 +1,19 @@ |
|||||
- name: Install pip |
|
||||
action: |
|
||||
module: "{{ ansible_pkg_mgr }}" |
|
||||
name: "python-pip" |
|
||||
state: latest |
|
||||
when: ansible_os_family != "CoreOS" and kpm_packages | length > 0 |
|
||||
|
--- |
||||
|
- name: Kubernetes Apps | Lay Down KubeDNS Template |
||||
|
template: src={{item.file}} dest=/etc/kubernetes/{{item.file}} |
||||
|
with_items: |
||||
|
- {file: kubedns-rc.yml, type: rc} |
||||
|
- {file: kubedns-svc.yml, type: svc} |
||||
|
register: manifests |
||||
|
when: inventory_hostname == groups['kube-master'][0] |
||||
|
|
||||
- name: install kpm |
|
||||
pip: |
|
||||
name: "kpm" |
|
||||
state: "latest" |
|
||||
when: kpm_packages | length > 0 |
|
||||
|
|
||||
- name: manage kubernetes applications |
|
||||
kpm: |
|
||||
namespace: "{{item.namespace | default(kpm_namespace | default('default'))}}" |
|
||||
registry: "{{item.registry | default(kpm_registry | default('https://api.kpm.sh'))}}" |
|
||||
state: "{{item.state | default(omit)}}" |
|
||||
version: "{{item.version | default(omit)}}" |
|
||||
variables: "{{item.variables | default(omit)}}" |
|
||||
name: "{{item.name}}" |
|
||||
with_items: "{{kpm_packages}}" |
|
||||
register: kpmresults |
|
||||
environment: |
|
||||
PATH: "{{ ansible_env.PATH }}:{{ bin_dir }}" |
|
||||
|
- name: Kubernetes Apps | Start Resources |
||||
|
kube: |
||||
|
name: KubeDNS |
||||
|
namespace: kube-system |
||||
|
kubectl: "{{bin_dir}}/kubectl" |
||||
|
resource: "{{item.item.type}}" |
||||
|
filename: /etc/kubernetes/{{item.item.file}} |
||||
|
state: "{{item.changed | ternary('latest','present') }}" |
||||
|
with_items: "{{ manifests.results }}" |
||||
|
when: inventory_hostname == groups['kube-master'][0] |
@ -0,0 +1,99 @@ |
|||||
|
apiVersion: v1 |
||||
|
kind: ReplicationController |
||||
|
metadata: |
||||
|
name: kube-dns-v19 |
||||
|
namespace: kube-system |
||||
|
labels: |
||||
|
k8s-app: kube-dns |
||||
|
version: v19 |
||||
|
kubernetes.io/cluster-service: "true" |
||||
|
spec: |
||||
|
replicas: 1 |
||||
|
selector: |
||||
|
k8s-app: kube-dns |
||||
|
version: v19 |
||||
|
template: |
||||
|
metadata: |
||||
|
labels: |
||||
|
k8s-app: kube-dns |
||||
|
version: v19 |
||||
|
kubernetes.io/cluster-service: "true" |
||||
|
spec: |
||||
|
containers: |
||||
|
- name: kubedns |
||||
|
image: gcr.io/google_containers/kubedns-amd64:1.6 |
||||
|
resources: |
||||
|
# TODO: Set memory limits when we've profiled the container for large |
||||
|
# clusters, then set request = limit to keep this container in |
||||
|
# guaranteed class. Currently, this container falls into the |
||||
|
# "burstable" category so the kubelet doesn't backoff from restarting it. |
||||
|
limits: |
||||
|
cpu: 100m |
||||
|
memory: 170Mi |
||||
|
requests: |
||||
|
cpu: 100m |
||||
|
memory: 70Mi |
||||
|
livenessProbe: |
||||
|
httpGet: |
||||
|
path: /healthz |
||||
|
port: 8080 |
||||
|
scheme: HTTP |
||||
|
initialDelaySeconds: 60 |
||||
|
timeoutSeconds: 5 |
||||
|
successThreshold: 1 |
||||
|
failureThreshold: 5 |
||||
|
readinessProbe: |
||||
|
httpGet: |
||||
|
path: /readiness |
||||
|
port: 8081 |
||||
|
scheme: HTTP |
||||
|
# we poll on pod startup for the Kubernetes master service and |
||||
|
# only setup the /readiness HTTP server once that's available. |
||||
|
initialDelaySeconds: 30 |
||||
|
timeoutSeconds: 5 |
||||
|
args: |
||||
|
# command = "/kube-dns" |
||||
|
- --domain={{ cluster_name }}. |
||||
|
- --dns-port=10053 |
||||
|
ports: |
||||
|
- containerPort: 10053 |
||||
|
name: dns-local |
||||
|
protocol: UDP |
||||
|
- containerPort: 10053 |
||||
|
name: dns-tcp-local |
||||
|
protocol: TCP |
||||
|
- name: dnsmasq |
||||
|
image: gcr.io/google_containers/kube-dnsmasq-amd64:1.3 |
||||
|
args: |
||||
|
- --cache-size=1000 |
||||
|
- --no-resolv |
||||
|
- --server=127.0.0.1#10053 |
||||
|
ports: |
||||
|
- containerPort: 53 |
||||
|
name: dns |
||||
|
protocol: UDP |
||||
|
- containerPort: 53 |
||||
|
name: dns-tcp |
||||
|
protocol: TCP |
||||
|
- name: healthz |
||||
|
image: gcr.io/google_containers/exechealthz-amd64:1.1 |
||||
|
resources: |
||||
|
# keep request = limit to keep this container in guaranteed class |
||||
|
limits: |
||||
|
cpu: 10m |
||||
|
memory: 50Mi |
||||
|
requests: |
||||
|
cpu: 10m |
||||
|
# Note that this container shouldn't really need 50Mi of memory. The |
||||
|
# limits are set higher than expected pending investigation on #29688. |
||||
|
# The extra memory was stolen from the kubedns container to keep the |
||||
|
# net memory requested by the pod constant. |
||||
|
memory: 50Mi |
||||
|
args: |
||||
|
- -cmd=nslookup kubernetes.default.svc.cluster.local 127.0.0.1 >/dev/null && nslookup kubernetes.default.svc.cluster.local 127.0.0.1:10053 >/dev/null |
||||
|
- -port=8080 |
||||
|
- -quiet |
||||
|
ports: |
||||
|
- containerPort: 8080 |
||||
|
protocol: TCP |
||||
|
dnsPolicy: Default # Don't use cluster DNS. |
@ -0,0 +1,20 @@ |
|||||
|
apiVersion: v1 |
||||
|
kind: Service |
||||
|
metadata: |
||||
|
name: kube-dns |
||||
|
namespace: kube-system |
||||
|
labels: |
||||
|
k8s-app: kube-dns |
||||
|
kubernetes.io/cluster-service: "true" |
||||
|
kubernetes.io/name: "KubeDNS" |
||||
|
spec: |
||||
|
selector: |
||||
|
k8s-app: kube-dns |
||||
|
clusterIP: {{ skydns_server }} |
||||
|
ports: |
||||
|
- name: dns |
||||
|
port: 53 |
||||
|
protocol: UDP |
||||
|
- name: dns-tcp |
||||
|
port: 53 |
||||
|
protocol: TCP |
Write
Preview
Loading…
Cancel
Save