Systemd service file doesn't read the environmentFile

I am trying to start etcd service and I have a environment variable file that I am referring by the systemd file.

First time it works fine and in the next time when I try to stop the service and do the same steps, it doesn't read the environmentFile and update the values.

Here's my /etc/etcd.conf where I put environment variables


INTERNAL_IP=$(ip -o route get to 8.8.8.8 | sed -n 's/.*src \([0-9.]\+\).*/\1/p')

cat << EOF > /etc/etcd.conf
#SELF_IP is the IP of the node where this file resides.
SELF_IP=$INTERNAL_IP
# IP of Node 1
NODE_1_IP=10.128.15.225
#IP of Node 2
NODE_2_IP=10.128.15.226
NODE_3_IP=10.128.15.227
EOF

This is my /etc/systemd/system/etcd3.service file

cat << EOF > /etc/systemd/system/etcd3.service
[Unit]
Description=etcd
Documentation=https://github.com/coreos/etcd
Conflicts=etcd.service
Conflicts=etcd2.service

[Service]
Type=notify
Restart=always
RestartSec=25s
LimitNOFILE=40000
TimeoutStartSec=1s
EnvironmentFile=/etc/etcd.conf
ExecStart=/bin/bash -c "/usr/local/bin/etcd --name etcd-${SELF_IP} --data-dir /var/lib/etcd --quota-backend-bytes 8589934592 --auto-compaction-retention 3 --listen-client-urls http://${SELF_IP}:2379,http://localhost:2379 --advertise-client-urls http://${SELF_IP}:2379,http://localhost:2379 --listen-peer-urls http://${SELF_IP}:2380 --initial-advertise-peer-urls http://${SELF_IP}:2380 --initial-cluster 'etcd-${NODE_1_IP}=http://${NODE_1_IP}:2380,etcd-${NODE_2_IP}=http://${NODE_2_IP}:2380,etcd-${NODE_3_IP}=http://${NODE_3_IP}:2380' --initial-cluster-token my-etcd-token --initial-cluster-state new"

[Install]
WantedBy=multi-user.target
EOF

Why this is working for the first time and not afterwards?

How can i stop the service successfully and try to create the /etc/etcd.conf with some additional values and start the same service

because it gives the below error:

-- Subject: Unit etcd3.service has begun start-up
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit etcd3.service has begun starting up.
Nov 19 15:08:59 etcd-1 etcd[2341]: error verifying flags, expected IP in URL for binding (http://:2380). See 'etcd --help'.
Nov 19 15:08:59 etcd-1 systemd[1]: etcd3.service: main process exited, code=exited, status=1/FAILURE
Nov 19 15:08:59 etcd-1 systemd[1]: Failed to start etcd.
-- Subject: Unit etcd3.service has failed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit etcd3.service has failed.
-- 
-- The result is failed.

and when I try to cat /etc/systemd/system/etcd3.service after the first time (i.e second time after executing the same commands), the values I have passed are not really shown their, instead it shows empty values, such as --name etcd-


There are 2 problems with the shell variables like ${SELF_IP} in the ExecStart= line. One is that

cat << EOF > /etc/systemd/system/etcd3.service

does variable interpolation, so the etcd3.service file will replace ${SELF_IP} by whatever its current value is, perhaps empty. The fix for this is to quote the EOF as in cat <<'EOF' for example.

The next problem will then be that systemd also interpolates variables of the form ${...} in the ExecStart= line, even when inside single or double quotes. So they will again be replaced by the current value for systemd (which uses the EnvironmentFile when running the command, not when parsing the line), so probably empty.

The fix for this is to double the $ signs on this line, eg $${SELF_IP}. If you use /bin/bash -cv as the command you should be able to see what command is passed to bash, and whether the variables have survived that far.