systemd – How to Set Environmental Variable in Systemd Service

environment-variablessystemd

I'm working with ROS, which has been installed on my Ubuntu correctly.

To run the ROS, we have to first source /opt/ros/kinetic/setup.bash then execute roscore. If I execute roscore without source setup.bash, the command roscore can't be found.

Now, I want to execute the ROS while the system starts up.

I've read this link: https://askubuntu.com/questions/814/how-to-run-scripts-on-start-up

It seems that I only need to create a custom service file and put it into /etc/systemd/system/. But still I'm not sure what to do because I need to source setup.bash to setup some necessary environmental variables before executing roscore.

Is it possible to set environmental variables in the service file? For my need, I have to set these environmental variables not only for the execution of roscore but also for the whole system.

I have another idea, which is that I set these environmental variables in /etc/profile and write a service file only for the command roscore, will it work?

Best Answer

Normally systemd services have only a limited set of environment variables, and things in /etc/profile, /etc/profile.d and bashrc-related files are not set.

To add environment variables for a systemd service you have different possibilities.

The examples as follows assume that roscore is at /opt/ros/kinetic/bin/roscore, since systemd services must have the binary or script configured with a full path.


One possibility is to use the Environment option in your systemd service and a simple systemd service would be as follows.

[root@localhost ~]# cat /etc/systemd/system/ros.service
[Unit]
Description=ROS Kinetic
After=sshd.service

[Service]
Type=simple
Environment="One=1" "Three=3"
Environment="Two=2"
Environment="Four=4"
ExecStart=/opt/ros/kinetic/bin/roscore

[Install]
WantedBy=multi-user.target

You also can put all the environment variables into a file that can be read with the EnvironmentFile option in the systemd service.

[root@localhost ~]# cat /etc/systemd/system/ros.env
One=1
Three=3
Two=2
Four=4


[root@localhost ~]# cat /etc/systemd/system/ros.service
[Unit]
Description=ROS Kinetic
After=sshd.service

[Service]
Type=simple
EnvironmentFile=/etc/systemd/systemd/ros.env
ExecStart=/opt/ros/kinetic/bin/roscore

[Install]
WantedBy=multi-user.target

Another option would be to make a wrapper script for your ros binary and call that wrapper script from the systemd service. The script needs to be executable.  To ensure that, run

chmod 755 /opt/ros/kinetic/bin/roscore.startup

after creating that file.

[root@localhost ~]# cat /opt/ros/kinetic/bin/roscore.startup
#!/bin/bash

source /opt/ros/kinetic/setup.bash
roscore


[root@localhost ~]# cat /etc/systemd/system/ros.service
[Unit]
Description=ROS Kinetic
After=sshd.service

[Service]
Type=simple
ExecStart=/opt/ros/kinetic/bin/roscore.startup

[Install]
WantedBy=multi-user.target

Note that you need to run systemctl daemon-reload after you have edited the service file to make the changes active. To enable the service on systemboot, you have to enter systemctl enable ros.

I am not familiar with the roscore binary and it might be necessary to change Type= from simple (which is the default and normally not needed) to forking in the first two examples.


For normal logins, you could copy or symlink /opt/ros/kinetic/setup.bash to /etc/profile.d/ros.sh, which should be sourced on normal logins.

Related Question