英文:
Linux System.d Unit Service Doesn't See My Specific Environment Variable
问题
我有一个类似下面的基本的"service unit"文件。
[Unit]
Description=Certprovider服务
After=network.target
[Service]
Type=simple
Restart=always
RestartSec=5s
ExecStart=/home/mert/certprovider/certprovider
WorkingDirectory=/home/mert
User=root
Group=root
[Install]
WantedBy=multi-user.target
我在项目的根目录下有一个.env文件。
CA_DIR_URL=https://acme-v02.api.letsencrypt.org/directory
EMAIL=mertsmsk0@gmail.com
HOST=127.0.0.1
PORT=8557
我使用以下代码加载这个文件。
err := godotenv.Load()
if err != nil {
log.Fatalln("加载.env文件时出错")
}
服务一直运行得很好,但我无法访问PORT环境变量。因此,我无法启动Web服务器,因为该端口无法监听。我打印了.env文件中除PORT之外的所有环境变量。我将其更改为APP_PORT,但结果相同。
奇怪的是,我可以访问.env文件中的其他变量。此外,当我在unit文件中添加以下行时,我可以访问该变量,但我不明白为什么只需要在unit文件中添加PORT变量。
[Service]
Environment=PORT=8557
这只发生在我尝试以二进制文件运行时。因为我可以使用以下命令访问这些变量。
go run .
英文:
I have a basic "service unit" file like the following.
[Unit]
Description=Certprovider service
After=network.target
[Service]
Type=simple
Restart=always
RestartSec=5s
ExecStart=/home/mert/certprovider/certprovider
WorkingDirectory=/home/mert
User=root
Group=root
[Install]
WantedBy=multi-user.target
I have the .env file in the root of the project.
CA_DIR_URL=https://acme-v02.api.letsencrypt.org/directory
EMAIL=mertsmsk0@gmail.com
HOST=127.0.0.1
PORT=8557
I load this file with the following lines.
err := godotenv.Load()
if err != nil {
log.Fatalln("Error loading .env file")
}
Service has been working very well but I cannot reach the PORT environment variable. Thus I cannot start the webserver because that port cannot listen. I print all the environment variables that in the .env excluding PORT. I changed its name to APP_PORT but it same thing.
The mystery part is I can reach other variables in the .env file. In addition to that when I add the following line in the unit file, I can reach that variable but I don't understand that why should I add only the PORT variable in the unit file?
[Service]
Environment=PORT=8557
It's happening when I try to run it as a binary file. Because I can reach the variables with the following command.
go run .
答案1
得分: 2
如果您调用Load而没有任何参数,它将默认加载当前路径中的.env文件。
您的当前路径在这里配置:
WorkingDirectory=/home/mert
然而,您说(重点添加)
> 我在项目的根目录中有.env文件。
但那不是当前工作目录。
> 项目的根目录
这个概念对应用程序运行时来说是没有意义的。与解释性语言(比如PHP)不同,Go编译为一个静态二进制文件,其功能与定义它的库和源代码集是完全不同的。在PHP(或Python、Ruby等)中,这些库没有其他地方可以存在,除了某个项目目录的根目录。
在Go中,这些东西只与开发和测试有关。您的可执行文件似乎在您的“项目根目录”中,这完全是偶然的,没有任何意义。
如果您真的想将运行时配置放在那个特定的文件中,在那个特定的位置,只需将那个文件设置为工作目录:
ExecStart=/home/mert/certprovider/certprovider
WorkingDirectory=/home/mert/certprovider/certprovider
我会将那些东西放在/usr/local
中,这样我就不会在我的主目录中无意中破坏我的Let's Encrypt证书,尤其是对于Let's Encrypt来说,因为可能需要长达90天才能意识到您的证书没有被刷新。出于同样的原因,我会将配置文件放在我的主目录之外。
实际上,对于这种情况,我可能会将所有配置都放在单元文件中。为什么不把它放在那里呢?当然,这是一个观点问题。如果您真的想使用自动的.env
发现功能,那么您应该专门为包含该隐藏文件的目录。在~/.env
中放置一个仅适用于一个应用程序的配置没有太多意义。
无论您将.env
放在哪里,请确保它是您的工作目录,以便它可以被发现。
> 我打印出了在.env文件中除了PORT之外的所有环境变量。我将其更改为APP_PORT,但结果相同。[...]
> 神秘的部分是,我可以访问.env文件中的其他变量。
恕我直言,这听起来像是您的假设。如果没有证据相反,很容易得出结论,您已经为这些值设置了默认值,或者它们来自其他来源或行为。这比得出结论说godotenv
库从文件中读取了一些但不是全部值更加简洁。
> 当我尝试以二进制文件运行时,就会发生这种情况。因为我可以通过以下命令访问变量。[go run .
]
Go始终作为二进制文件运行。go run .
只是自动在临时位置构建二进制文件,然后运行它。https://stackoverflow.com/questions/61060768/why-is-it-recommended-to-use-go-build-instead-of-go-run-when-running-a-go-ap讨论了为什么在SO上通常不推荐使用go run
的原因。
英文:
If you call Load without any args it will default to loading env in the current path.
Your current path is configured here:
WorkingDirectory=/home/mert
And yet, you say (emphasis added)
> I have the .env file in the root of the project.
But that's not the current working directory.
> root of the project
That concept is not meaningful to the application runtime. Unlike interpreted languages like, say, PHP, Go compiles to a static binary that is functionally entirely distinct from the set of libraries and sources that define it. In PHP (or python, ruby, etc) those libraries have no other place to be, than the root of some project directory.
In go, that stuff is only relevant for development and testing. The fact that your executable appears to be in your "root of the project" is entirely incidental and completely meaningless.
If you really want to put the runtime configuration in tht particular file, in that particular place, just set that as the working directory:
ExecStart=/home/mert/certprovider/certprovider
WorkingDirectory=/home/mert/certprovider/certprovider
I would put that stuff in /usr/local
so I didn't accidentally break my let's encrypt while fiddling with stuff in my home directory - doubly so for let's encrypt because it might take up to 90 days to realize your certs weren't being refreshed. I'd put the config outside of my home directory for the same reason.
Actually, for this case I'd probably put all the config in the unit file. Why not put it there? But of course, that's a matter of opinion. If you really want to use the automatic .env
discovery then you should dedicate a directory to containing that hidden file. It doesn't make much sense to put a config specific to one application in ~/.env
.
Wherever you put .env
, make sure that's your working directory so it will be discovered.
> I print all the environment variables that in the .env excluding PORT. I changed its name to APP_PORT but it same thing. [...]
> The mystery part is I can reach other variables in the .env file.
Respectfully, that sounds like an assumption on your part. Without evidence to the contrary, it's easy to conclude that you have set defaults for these values or that they're coming from some other source or behavior. That's more parsimonious than concluding the godotenv
library read some, but not all, the values from a file.
> It's happening when I try to run it as a binary file. Because I can reach the variables with the following command. [go run .
]
Go always runs as a binary. go run .
simply automatically builds the binary in a temp location and then runs it. https://stackoverflow.com/questions/61060768/why-is-it-recommended-to-use-go-build-instead-of-go-run-when-running-a-go-ap talks about why go run
is often contraindicated on SO.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论