A couple of years late to reply, but here is what I did for a similar case.
If you don't want to use LoadBalancer
at all, then the other option is NodePort
as you mention. To make it externally addressable, you can have the pod associate a static IP to its node when it comes up. For example in AWS EC2 you can have an elastic IP (or static external IP in GCP) and associate it when the postgresql pod comes up in its PodSpec
using initContainers or a separate container:
initContainers:
- name: eip
image: docker.io/amazon/aws-cli:2.7.1
command:
- /bin/bash
- -xec
- |
INSTANCE_ID="$(curl http://169.254.169.254/latest/meta-data/instance-id)"
aws ec2 associate-address --allocation-id "$EIP_ALLOCATION_ID" --instance-id "$INSTANCE_ID"
env:
- name: EIP_ALLOCATION_ID
value: <your elastic IP allocation ID>
- name: AWS_REGION
value: <region>
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: aws-secret
key: accessKey
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: aws-secret
key: secretKey
Here AWS access key and secret key are assumed to be installed in aws-secret
. Above example uses environment variables but to be more secure you can instead mount on a volume and read in the script body and unset after use.
To alleviate the security concerns related to ports, one option can be to add only a node or two to the security group exposing the port, and use nodeSelector for the pod to stick it to only those nodes. Alternatively you can use "aws ec2 modify-instance-attribute" in the container body above to add the security group to just the node running the pod. Below is a more complete example for AWS EC2 that handles a node having multiple network interfaces:
containers:
- name: eip-sg
image: docker.io/amazon/aws-cli:2.7.1
command:
- /bin/bash
- -xec
- |
INSTANCE_ID=$(curl http://169.254.169.254/latest/meta-data/instance-id)
PRIVATE_IP="$(curl http://169.254.169.254/latest/meta-data/local-ipv4)"
for iface in $(curl http://169.254.169.254/latest/meta-data/network/interfaces/macs/); do
if curl "http://169.254.169.254/latest/meta-data/network/interfaces/macs/$iface/local-ipv4s" | grep -q "$PRIVATE_IP"; then
INTERFACE_FOR_IP="$(curl http://169.254.169.254/latest/meta-data/network/interfaces/macs/$iface/interface-id)"
fi
done
if [ -z "$INTERFACE_FOR_IP" ]; then
aws ec2 associate-address --allocation-id "$EIP_ALLOCATION_ID" --instance-id "$INSTANCE_ID"
else
aws ec2 associate-address --allocation-id "$EIP_ALLOCATION_ID" --network-interface-id "$INTERFACE_FOR_IP" --private-ip-address "$PRIVATE_IP"
fi
aws ec2 modify-instance-attribute --instance-id "$INSTANCE_ID" --groups $FULL_SECURITY_GROUPS
tail -f -s 10 /dev/null
lifecycle:
preStop:
exec:
command:
- /bin/bash
- -ec
- |
INSTANCE_ID=$(curl http://169.254.169.254/latest/meta-data/instance-id)
aws ec2 modify-instance-attribute --instance-id "$INSTANCE_ID" --groups $DEFAULT_SECURITY_GROUPS
env:
- name: EIP_ALLOCATION_ID
value: <your elastic IP allocation ID>
- name: DEFAULT_SECURITY_GROUPS
value: "<sg1> <sg2>"
- name: FULL_SECURITY_GROUPS
value: "<sg1> <sg2> <sg3>"
- name: AWS_REGION
value: <region>
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: aws-secret
key: accessKey
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: aws-secret
key: secretKey
You may also need to set the deployment strategy
to be Recreate
instead of the default of RollingUpdate
otherwise the lifecycle.preStop
may get invoked after the container command
in case the deployment is restarted using kubectl rollout restart deployment ...
.