diff --git a/installer/install.yml b/installer/install.yml index d37d3af596..082a1b24c6 100644 --- a/installer/install.yml +++ b/installer/install.yml @@ -6,4 +6,5 @@ - { role: check_vars } - { role: image_build, when: "dockerhub_base is not defined" } - { role: openshift, when: "openshift_host is defined" } - - { role: local_docker, when: "openshift_host is not defined" } + - { role: kubernetes, when: "kubernetes_context is defined" } + - { role: local_docker, when: "openshift_host is not defined and kubernetes_context is not defined" } diff --git a/installer/inventory b/installer/inventory index e0169706d1..e4fd789a95 100644 --- a/installer/inventory +++ b/installer/inventory @@ -26,6 +26,11 @@ awx_secret_key=awxsecret # openshift_user=developer # awx_node_port=30083 +# Kubernetes Install +# kubernetes_context=test-cluster +# awx_kubernetes_namespace=awx +# awx_node_port=30083 + # Standalone Docker Install postgres_data_dir=/tmp/pgdocker host_port=80 diff --git a/installer/kubernetes/tasks/main.yml b/installer/kubernetes/tasks/main.yml new file mode 100644 index 0000000000..b7046196c3 --- /dev/null +++ b/installer/kubernetes/tasks/main.yml @@ -0,0 +1,125 @@ +--- +- name: Set the Kubernetes Context + shell: "kubectl config set-context {{ kubernetes_context }}" + +- name: Get Namespace Detail + shell: "kubectl get namespace {{ awx_kubernetes_namespace }}" + register: namespace_details + ignore_errors: yes + +- name: Get Postgres Service Detail + shell: "kubectl describe svc awx-postgresql -n {{ awx_kubernetes_namespace }}" + register: postgres_svc_details + ignore_errors: yes + when: "pg_hostname is not defined or pg_hostname == ''" + +- name: Create AWX Kubernetes Project + shell: "kubectl create namespace {{ awx_kubernetes_namespace }}" + when: namespace_details.rc != 0 + +# TODO: This is duplicated in the openshift role, probably needs to be moved to the image_build role +- name: Manage AWX Container Images + block: + - name: Get docker registry password from oc if needed + block: + - name: Set docker registry password + shell: oc whoami -t + register: docker_registry_password_shell + - name: Set docker registry password + set_fact: + docker_registry_password: "{{ docker_registry_password_shell.stdout }}" + when: docker_registry_password is not defined + + - name: Authenticate with Docker registry + docker_login: + registry: "{{ docker_registry }}" + username: "{{ docker_registry_username }}" + password: "{{ docker_registry_password }}" + reauthorize: yes + when: docker_registry is defined and docker_registry_password is defined + delegate_to: localhost + + - name: Wait for Openshift + pause: + seconds: 30 + + - name: Tag and push web image to registry + docker_image: + name: "{{ awx_web_image }}" + repository: "{{ docker_registry }}/{{ docker_registry_repository }}/{{ awx_web_image }}" + tag: "{{ awx_version }}" + push: yes + when: docker_registry is defined + delegate_to: localhost + + - name: Wait for the registry to settle + pause: + seconds: 10 + + - name: Tag and push task image to registry + docker_image: + name: "{{ awx_task_image }}" + repository: "{{ docker_registry }}/{{ docker_registry_repository }}/{{ awx_task_image }}" + tag: "{{ awx_version }}" + push: yes + when: docker_registry is defined + delegate_to: localhost + + - name: Set full web image path + set_fact: + awx_web_kubernetes_image: "{{ awx_web_image }}:{{ awx_version }}" + when: awx_web_kubernetes_image is not defined + + - name: Set full task image path + set_fact: + awx_task_kubernetes_image: "{{ awx_task_image }}:{{ awx_version }}" + when: awx_task_kubernetes_image is not defined + when: dockerhub_base is not defined + +- name: Set DockerHub Image Paths + set_fact: + awx_web_kubernetes_image: "{{ dockerhub_base }}/awx_web:{{ dockerhub_version }}" + awx_task_kubernetes_image: "{{ dockerhub_base }}/awx_task:{{ dockerhub_version }}" + when: dockerhub_base is defined + +- name: Deploy and Activate Postgres + shell: "helm install --name awx --namespace {{ awx_kubernetes_namespace }} --set postgresUser={{ pg_username }},postgresPassword={{ pg_password }},postgresDatabase={{ pg_database }},persistence.size={{ pg_volume_capacity|default('5')}}Gi stable/postgresql" + when: (pg_hostname is not defined or pg_hostname == '') and (postgres_svc_details is defined and postgres_svc_details.rc != 0) + register: kubernetes_pg_activate + +- name: Set postgresql hostname to helm package service + set_fact: + pg_hostname: awx-postgresql + when: pg_hostname is not defined or pg_hostname == '' + +- name: Wait for Postgres to activate + pause: + seconds: 60 + when: kubernetes_pg_activate|changed + +- name: Set kubernetes base path + set_fact: + kubernetes_base_path: "{{ awx_local_base_config_path|default('/tmp') }}/awx-config" + +- name: Ensure directory exists + file: + path: "{{ kubernetes_base_path }}" + state: directory + +- name: Template Kubernetes AWX Config + template: + src: configmap.yml.j2 + dest: "{{ kubernetes_base_path }}/configmap.yml" + mode: '0600' + +- name: Template Kubernetes AWX Deployment + template: + src: deployment.yml.j2 + dest: "{{ kubernetes_base_path }}/deployment.yml" + mode: '0600' + +- name: Apply Configmap + shell: "kubectl apply -f {{ kubernetes_base_path }}/configmap.yml" + +- name: Apply Deployment + shell: "kubectl apply -f {{ kubernetes_base_path }}/deployment.yml" diff --git a/installer/kubernetes/templates/configmap.yml.j2 b/installer/kubernetes/templates/configmap.yml.j2 new file mode 100644 index 0000000000..539c3e43ef --- /dev/null +++ b/installer/kubernetes/templates/configmap.yml.j2 @@ -0,0 +1,95 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: awx-config + namespace: {{ awx_kubernetes_namespace }} +data: + secret_key: {{ awx_secret_key }} + awx_settings: | + import os + import socket + ADMINS = () + + # Container environments don't like chroots + AWX_PROOT_ENABLED = False + + #Autoprovisioning should replace this + CLUSTER_HOST_ID = socket.gethostname() + SYSTEM_UUID = '00000000-0000-0000-0000-000000000000' + + CELERY_TASK_QUEUES += (Queue(CLUSTER_HOST_ID, Exchange(CLUSTER_HOST_ID), routing_key=CLUSTER_HOST_ID),) + CELERY_TASK_ROUTES['awx.main.tasks.cluster_node_heartbeat'] = {'queue': CLUSTER_HOST_ID, 'routing_key': CLUSTER_HOST_ID} + CELERY_TASK_ROUTES['awx.main.tasks.purge_old_stdout_files'] = {'queue': CLUSTER_HOST_ID, 'routing_key': CLUSTER_HOST_ID} + STATIC_ROOT = '/var/lib/awx/public/static' + PROJECTS_ROOT = '/var/lib/awx/projects' + JOBOUTPUT_ROOT = '/var/lib/awx/job_status' + SECRET_KEY = file('/etc/tower/SECRET_KEY', 'rb').read().strip() + ALLOWED_HOSTS = ['*'] + INTERNAL_API_URL = 'http://127.0.0.1:8052' + AWX_TASK_ENV['HOME'] = '/var/lib/awx' + SERVER_EMAIL = 'root@localhost' + DEFAULT_FROM_EMAIL = 'webmaster@localhost' + EMAIL_SUBJECT_PREFIX = '[AWX] ' + EMAIL_HOST = 'localhost' + EMAIL_PORT = 25 + EMAIL_HOST_USER = '' + EMAIL_HOST_PASSWORD = '' + EMAIL_USE_TLS = False + + LOGGING['handlers']['console'] = { + '()': 'logging.StreamHandler', + 'level': 'DEBUG', + 'formatter': 'simple', + } + + LOGGING['loggers']['django.request']['handlers'] = ['console'] + LOGGING['loggers']['rest_framework.request']['handlers'] = ['console'] + LOGGING['loggers']['awx']['handlers'] = ['console'] + LOGGING['loggers']['awx.main.commands.run_callback_receiver']['handlers'] = ['console'] + LOGGING['loggers']['awx.main.commands.inventory_import']['handlers'] = ['console'] + LOGGING['loggers']['awx.main.tasks']['handlers'] = ['console'] + LOGGING['loggers']['awx.main.scheduler']['handlers'] = ['console'] + LOGGING['loggers']['django_auth_ldap']['handlers'] = ['console'] + LOGGING['loggers']['social']['handlers'] = ['console'] + LOGGING['loggers']['system_tracking_migrations']['handlers'] = ['console'] + LOGGING['loggers']['rbac_migrations']['handlers'] = ['console'] + LOGGING['loggers']['awx.isolated.manager.playbooks']['handlers'] = ['console'] + LOGGING['handlers']['callback_receiver'] = {'class': 'logging.NullHandler'} + LOGGING['handlers']['fact_receiver'] = {'class': 'logging.NullHandler'} + LOGGING['handlers']['task_system'] = {'class': 'logging.NullHandler'} + LOGGING['handlers']['tower_warnings'] = {'class': 'logging.NullHandler'} + LOGGING['handlers']['rbac_migrations'] = {'class': 'logging.NullHandler'} + LOGGING['handlers']['system_tracking_migrations'] = {'class': 'logging.NullHandler'} + LOGGING['handlers']['management_playbooks'] = {'class': 'logging.NullHandler'} + + DATABASES = { + 'default': { + 'ATOMIC_REQUESTS': True, + 'ENGINE': 'django.db.backends.postgresql', + 'NAME': "{{ pg_database }}", + 'USER': "{{ pg_username }}", + 'PASSWORD': "{{ pg_password }}", + 'HOST': "{{ pg_hostname|default('postgresql') }}", + 'PORT': "{{ pg_port }}", + } + } + CELERY_BROKER_URL = 'amqp://{}:{}@{}:{}/{}'.format( + "awx", + "abcdefg", + "localhost", + "5672", + "awx") + CHANNEL_LAYERS = { + 'default': {'BACKEND': 'asgi_amqp.AMQPChannelLayer', + 'ROUTING': 'awx.main.routing.channel_routing', + 'CONFIG': {'url': CELERY_BROKER_URL}} + } + CACHES = { + 'default': { + 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', + 'LOCATION': '{}:{}'.format("localhost", "11211") + }, + 'ephemeral': { + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', + }, + } diff --git a/installer/kubernetes/templates/deployment.yml.j2 b/installer/kubernetes/templates/deployment.yml.j2 new file mode 100644 index 0000000000..8b7b0580f8 --- /dev/null +++ b/installer/kubernetes/templates/deployment.yml.j2 @@ -0,0 +1,92 @@ +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: awx + namespace: {{ awx_kubernetes_namespace }} +spec: + replicas: 1 + template: + metadata: + labels: + name: awx-web-deploy + service: django + spec: + containers: + - name: awx-web + image: {{ awx_web_kubernetes_image }} + ports: + - containerPort: 8052 + volumeMounts: + - mountPath: /etc/tower + name: awx-application-config + - name: awx-celery + image: {{ awx_task_kubernetes_image }} + volumeMounts: + - mountPath: /etc/tower + name: awx-application-config + env: + - name: DATABASE_USER + value: {{ pg_username }} + - name: DATABASE_NAME + value: {{ pg_database }} + - name: DATABASE_HOST + value: {{ pg_hostname|default('postgresql') }} + - name: DATABASE_PORT + value: ({{ pg_port|default('5432') }}) + - name: DATABASE_PASSWORD + value: {{ pg_password }} + - name: AWX_ADMIN_USER + value: {{ default_admin_user|default('admin') }} + - name: AWX_ADMIN_PASSWORD + value: {{ default_admin_password|default('password') }} + - name: awx-rabbit + image: rabbitmq:3 + env: + - name: RABBITMQ_ERLANG_COOKIE + value: secretb + - name: RABBITMQ_NODENAME + value: rabbitmq + - name: RABBITMQ_DEFAULT_USER + value: awx + - name: RABBITMQ_DEFAULT_PASS + value: abcdefg + - name: RABBITMQ_DEFAULT_VHOST + value: awx + - name: awx-memcached + image: memcached + volumes: + - name: awx-application-config + configMap: + name: awx-config + items: + - key: awx_settings + path: settings.py + - key: secret_key + path: SECRET_KEY +--- +apiVersion: v1 +kind: Service +metadata: + name: awx-web-svc + namespace: {{ awx_kubernetes_namespace }} + labels: + name: awx-web-svc +spec: + type: "NodePort" + ports: + - name: http + port: 80 + targetPort: 8052 + selector: + name: awx-web-deploy +--- +apiVersion: extensions/v1beta1 +kind: Ingress +metadata: + name: awx-web-svc + namespace: {{ awx_kubernetes_namespace }} +spec: + backend: + serviceName: awx-web-svc + servicePort: 80 diff --git a/installer/openshift/tasks/main.yml b/installer/openshift/tasks/main.yml index 4054a9db46..0de60caa98 100644 --- a/installer/openshift/tasks/main.yml +++ b/installer/openshift/tasks/main.yml @@ -21,6 +21,7 @@ - name: Mark Openshift User as Admin shell: "oc adm policy add-role-to-user admin {{ openshift_user }} -n {{ awx_openshift_project }}" +# TODO: This is duplicated in the kubernetes role, probably needs to be moved to the image_build role - name: Manage AWX Container Images block: - name: Get docker registry password from oc if needed @@ -55,7 +56,7 @@ when: docker_registry is defined delegate_to: localhost - - name: Wait for openshift + - name: Wait for the registry to settle pause: seconds: 10 @@ -68,6 +69,7 @@ when: docker_registry is defined delegate_to: localhost + # Note this is the one bit that is Openshift specific - name: Enable image stream lookups for awx images shell: "oc set image-lookup --all -n {{ awx_openshift_project }}"