-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Chris Vermeulen
committed
Aug 8, 2018
0 parents
commit 0fd99e6
Showing
6 changed files
with
199 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/.idea/ | ||
/.DS_store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
FROM ubuntu:16.04 | ||
|
||
WORKDIR /code | ||
|
||
RUN apt-get update && \ | ||
apt-get install -y apt-transport-https curl python3-dev nginx && \ | ||
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \ | ||
touch /etc/apt/sources.list.d/kubernetes.list && \ | ||
echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list && \ | ||
apt-get update && \ | ||
apt-get install -y kubectl=1.11.1-00 | ||
|
||
COPY . /code | ||
|
||
RUN chmod +x map_services.py entrypoint.sh | ||
|
||
ENTRYPOINT sh entrypoint.sh |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
# Kubernetes port forward utility | ||
|
||
> When developing services locally, we sometimes require dependant services to be proxied from our cluster to our local machine to ease development. | ||
> This image serves the purpose of easing that process. | ||
### Usage | ||
|
||
The image uses the environment variable $SERVICES to see which services you need proxied. | ||
|
||
This variable should contain a comma-delimited list of deployments & ports to forward | ||
|
||
The format for this variable is DEPLOYMENT_NAME:PORT:TARGET_PORT, OTHER_DEPLOYMENT:PORT:TARGET_PORT etc. | ||
|
||
TARGET_PORT is optional. If none is supplied the image will use PORT as both remote and local port. | ||
|
||
In your docker-compose file you can simply add: | ||
```yaml | ||
kube-forwards: | ||
image: chris-cmsoft/kube_forward:1.0.2 | ||
environment: | ||
- SERVICES=someservice:8000, someotherservice:8001:8000 | ||
volumes: | ||
- ~/.kube/config:/root/.kube/config | ||
some-service: | ||
image: some-image:1.0 | ||
``` | ||
Now if you exec into the some-service container you can curl http://kube-forwards:8000 and it will hit someservice on the Kubernetes cluster. | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
version: '2' | ||
|
||
services: | ||
kube_forwards: | ||
build: . | ||
entrypoint: ['tail', '-f', '/dev/null'] | ||
environment: | ||
- SERVICES=authenticationservice:8000, srservice:8001:8000 | ||
ports: | ||
- 8011:8000 | ||
- 8012:8001 | ||
volumes: | ||
- ~/.kube/config:/root/.kube/config | ||
- .:/code | ||
networks: | ||
- default | ||
|
||
networks: | ||
default: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#!/usr/bin/env bash | ||
|
||
python3 map_services.py && tail -f port-log.txt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
#!/usr/bin/env python3 | ||
|
||
""" | ||
Library to find deployments that need to be proxied | ||
options: (To be specified as environment variables) | ||
SERVICES: The deployments that need to be proxied | ||
This script will look for the first running container and proxy that through to the machine. | ||
""" | ||
|
||
import os | ||
import logging | ||
from subprocess import run, PIPE, Popen | ||
|
||
|
||
nginx_directives = '' | ||
|
||
def validate_service_spec(service_spec): | ||
""" | ||
Valid service entries are services with: | ||
* A deployment name | ||
* At least one port | ||
Allowed additions: | ||
* second port for local machine | ||
""" | ||
service_parts = service_spec.strip().split(':') | ||
|
||
# There have to be at least two parts to the string | ||
if len(service_parts) <= 1: | ||
logging.warn('Service spec needs at lease one deployment name & port in the format NAME:PORT') | ||
logging.error( | ||
'Service: (' + service_spec + ') does not comply with standard. service needs to be secified in the ' | ||
'format NAME:TARGET_PORT:PORT_FORWARD_PORT(optional).') | ||
exit(1) | ||
|
||
if len(service_parts[0]) <= 0: | ||
logging.warn('Service name must be string') | ||
logging.error('Service: (' + service_spec + ') does not comply with standard.') | ||
exit(1) | ||
|
||
if not service_parts[1].isdigit(): | ||
logging.warn('Service port must be integer') | ||
logging.error('Service: (' + service_spec + ') does not comply with standard. (' + service_parts[ | ||
1] + ') os not a valid integer.') | ||
exit(1) | ||
|
||
if len(service_parts) >= 3 and not service_parts[2].isdigit(): | ||
logging.warn('Service port must be integer') | ||
logging.error('Service: (' + service_spec + ') does not comply with standard. (' + service_parts[ | ||
2] + ') os not a valid integer.') | ||
exit(1) | ||
|
||
return True | ||
|
||
|
||
def port_forward_service(service_spec): | ||
# kubectl get pods --selector=app=authenticationservice --output=jsonpath={.items..metadata.name} | ||
|
||
service_parts = service_spec.strip().split(':') | ||
|
||
output = run(['kubectl', 'get', 'pods', '--selector=app={}'.format(service_parts[0].strip()), | ||
'--output=jsonpath={.items..metadata.name}'], stdout=PIPE) | ||
|
||
if not output.stdout.decode().strip(): | ||
logging.error('No pods found for selector {}'.format(service_parts[0])) | ||
exit(1) | ||
|
||
local_port = service_parts[1] | ||
local_proxy_port = int(local_port) + 1000 | ||
remote_port = local_port if (len(service_parts) == 2) else service_parts[2] | ||
global nginx_directives | ||
nginx_directives += """ | ||
server {{ | ||
listen {listen_port}; | ||
server_name _; | ||
location / {{ | ||
proxy_pass http://127.0.0.1:{proxy_port}; | ||
proxy_pass_header Server; | ||
proxy_set_header Host $http_host; | ||
proxy_set_header X-Real-IP $remote_addr; | ||
proxy_set_header X-Scheme $scheme; | ||
proxy_set_header X-Forwarded-Proto https; | ||
}} | ||
}} | ||
""".format(listen_port=local_port, proxy_port=local_proxy_port) | ||
|
||
Popen('kubectl port-forward {} {}:{} >> port-log.txt &'.format( | ||
output.stdout.decode().strip(), | ||
local_proxy_port, | ||
service_parts[1] if (len(service_parts) == 2) else service_parts[2] | ||
), close_fds=True, shell=True) | ||
|
||
print('Port Forwarding: {} to local port {} from port {}'.format( | ||
service_parts[0], # Service name | ||
local_port, # Local Port | ||
remote_port, | ||
)) | ||
|
||
def update_nginx_configs(): | ||
file = open('/etc/nginx/sites-enabled/default', 'w+') | ||
file.truncate(0) | ||
file.write(nginx_directives) | ||
file.close() | ||
|
||
|
||
if __name__ == "__main__": | ||
services = os.environ.get('SERVICES', None) | ||
|
||
if not services: | ||
print('In order to proxy services, you need to specify the SERVICES environment variable.') | ||
exit(0) | ||
|
||
service_list = services.split(',') | ||
|
||
for service in service_list: | ||
# Validate will throw error and exit if services i oncorrectly defined. | ||
validate_service_spec(service) | ||
|
||
for service in service_list: | ||
port_forward_service(service) | ||
|
||
update_nginx_configs() | ||
|
||
Popen('service nginx restart', shell=True) |