-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathmy-cni-plugin
executable file
·156 lines (127 loc) · 6.15 KB
/
my-cni-plugin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/bin/bash
# Direct file descriptors 1 and 2 to log file, and file descriptor 3 to stdout
exec 3>&1
exec &>>/var/log/my-cni-plugin.log
# Write line to log file (file descriptor 1 is redirected to log file)
log() {
echo -e "$(date): $*"
}
# Read NetConf from stdin and extract custom fields. Example NetConf:
# {
# "cniVersion": "0.3.1",
# "name": "my-pod-network",
# "type": "my-cni-plugin",
# "myHostNetwork": "10.0.0.0/16",
# "myPodNetwork": "200.200.0.0/16",
# "myPodSubnet": "200.200.1.0/24"
# }
netconf=$(cat /dev/stdin)
host_network=$(jq -r ".myHostNetwork" <<<"$netconf")
pod_network=$(jq -r ".myPodNetwork" <<<"$netconf")
pod_subnet=$(jq -r ".myPodSubnet" <<<"$netconf")
# Prepare NetConf for host-local IPAM plugin (add 'ipam' field)
ipam_netconf=$(jq ". += {ipam:{subnet:\"$pod_subnet\"}}" <<<"$netconf")
# Write environment variables and NetConf to log file
log "CNI_COMMAND=$CNI_COMMAND, CNI_CONTAINERID=$CNI_CONTAINERID, CNI_NETNS=$CNI_NETNS, CNI_IFNAME=$CNI_IFNAME, CNI_PATH=$CNI_PATH\n$netconf"
# Execute the requested CNI operation
case "$CNI_COMMAND" in
#----------------------------------------------------------------------------#
# Pod creation
#----------------------------------------------------------------------------#
ADD)
#--------------------------------------------------------------------------#
# Invoke IPAM plugin
#--------------------------------------------------------------------------#
# Invoke host-local IPAM plugin to allocate IP address for Pod
# Example response:
# {
# "cniVersion": "0.3.1",
# "ips": [
# {
# "version": "4",
# "address": "200.200.0.2/24",
# "gateway": "200.200.0.1"
# }
# ],
# "dns": {}
# }
ipam_response=$(/opt/cni/bin/host-local <<<"$ipam_netconf")
# Extract IP addresses for Pod and gateway (bridge) from IPAM response
pod_ip=$(jq -r '.ips[0].address' <<<"$ipam_response")
bridge_ip=$(jq -r '.ips[0].gateway' <<<"$ipam_response")
#--------------------------------------------------------------------------#
# Do one-time setup
#--------------------------------------------------------------------------#
# The lock provides mutual exclusivity (at most one process in the critical
# section) and synchronisation (no process reaches the Pod-specific setup
# before the one-time setup has been fully completed at least once).
{
# Acquire lock, or wait if it is already taken
flock 100
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# Begin of critical section
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# Create bridge only if it doesn't yet exist
if ! ip link show cni0 &>/dev/null; then
ip link add cni0 type bridge
ip address add "$bridge_ip"/"${pod_subnet#*/}" dev cni0
ip link set cni0 up
fi
# Create an iptables rule only if it doesn't yet exist
ensure() {
eval "$(sed 's/-A/-C/' <<<"$@")" &>/dev/null || eval "$@"
}
# Allow forwarding of packets in default network namespace to/from Pods
ensure iptables -A FORWARD -s "$pod_network" -j ACCEPT
ensure iptables -A FORWARD -d "$pod_network" -j ACCEPT
# Set up NAT for traffic leaving the cluster (replace Pod IP with node IP)
iptables -t nat -N MY_CNI_MASQUERADE &>/dev/null
ensure iptables -t nat -A MY_CNI_MASQUERADE -d "$pod_network" -j RETURN
ensure iptables -t nat -A MY_CNI_MASQUERADE -d "$host_network" -j RETURN
ensure iptables -t nat -A MY_CNI_MASQUERADE -j MASQUERADE
ensure iptables -t nat -A POSTROUTING -s "$pod_subnet" -j MY_CNI_MASQUERADE
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# End of critical section
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
} 100>/tmp/my-cni-plugin.lock
#--------------------------------------------------------------------------#
# Do Pod-specific setup
#--------------------------------------------------------------------------#
# Create named link to Pod network namespace (for 'ip' command)
mkdir -p /var/run/netns/
ln -sf "$CNI_NETNS" /var/run/netns/"$CNI_CONTAINERID"
# Create veth pair in Pod network namespace
host_ifname=veth$RANDOM
ip netns exec "$CNI_CONTAINERID" ip link add "$CNI_IFNAME" type veth peer name "$host_ifname"
# Move host-end of veth pair to default network namespace and connect to bridge
ip netns exec "$CNI_CONTAINERID" ip link set "$host_ifname" netns 1
ip link set "$host_ifname" master cni0 up
# Assign IP address selected by IPAM plugin to Pod-end of veth pair
ip netns exec "$CNI_CONTAINERID" ip address add "$pod_ip" dev "$CNI_IFNAME"
ip netns exec "$CNI_CONTAINERID" ip link set "$CNI_IFNAME" up
# Create default route to bridge in Pod network namespace
ip netns exec "$CNI_CONTAINERID" ip route add default via "$bridge_ip" dev "$CNI_IFNAME"
#--------------------------------------------------------------------------#
# Return response
#--------------------------------------------------------------------------#
# Create response by adding 'interfaces' field to response of IPAM plugin
response=$(jq ". += {interfaces:[{name:\"$CNI_IFNAME\",sandbox:\"$CNI_NETNS\"}]} | .ips[0] += {interface:0}" <<<"$ipam_response")
log "Response:\n$response"
echo "$response" >&3
;;
#----------------------------------------------------------------------------#
# Pod deletion
#----------------------------------------------------------------------------#
DEL)
# Invoke host-local IPAM plugin to release IP address of Pod
/opt/cni/bin/host-local <<<"$ipam_netconf"
# Delete named link to network namespace that was created by ADD
rm -f /var/run/netns/"$CNI_CONTAINERID"
;;
#----------------------------------------------------------------------------#
# Report CNI specification version
#----------------------------------------------------------------------------#
VERSION)
echo '{"cniVersion":"0.3.1","supportedVersions":["0.1.0","0.2.0","0.3.0","0.3.1"]}' >&3
;;
esac