Where to put global config files for a Go program? (bonus points for not using a makefile)

agolangf · · 892 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>Hi, I&#39;m building a small <a href="https://github.com/cdiener/govitae">Go program</a> to generate resumes that requires some template files in order to generate its output. Right now I use a somewhat ugly way which extracts the GOPATH from the environment and looks for the templates in the project directory. However, I would like a more stable method, since the GOPATH method will fail if the GOPATH is not correctly set and maybe problematic for binary deployments. It seems to me that Makefiles are not really go-like, so what would be your recommended method to deal with global files required for a go binary? </p> <hr/>**评论:**<br/><br/>pollodelamuerte: <pre><p>Use the flags package and make it a command that you pass in when the program executes.</p> <p>Or just tell it where your config file lives via the flag and roll with that.</p></pre>pollodeldiablo: <pre><p>Also though about that. Use a flag with a sensible default value. The only downside I see is that either the user has to copy the files by hand or I have to install them which requires some kind of script again (specific to your OS). Thx. </p></pre>drjokepu: <pre><p>Environment variable with a sensible default in its absence, such as ~/.yourprogram/ or something similar?</p></pre>iambryanl: <pre><p>I second environment variables. At the day job, we use env vars with a custom wrapper script for all our Go apps. We create an /etc/DO/&lt;app name&gt; with a settings.yml in it, and then have a doexec script which execs the binary with the proper settings. Instead of stdlib flag, we use <a href="https://github.com/ianschenck/envflag/tree/master">https://github.com/ianschenck/envflag/tree/master</a>.</p></pre>bkeroack: <pre><p>Agreed. Use env vars for all configuration if at all possible. It makes your app stateless and easier to containerize (just one example advantage).</p></pre>pollodeldiablo: <pre><p>Sounds good. Does this work with Windows as well? I would guess at least that setting the environment variable might be more difficult there. But I could check whether it is set and if not use a default location depending on the detected OS...</p></pre>damian2000: <pre><p>Yes, you can have a windows batch file (.bat) where you setup the environment variables and then run the go program. You can also set Current User or Machine environment variables via the System dialog in the Control Panel. Likely possible via PowerShell as well if you use that.</p></pre>AYBABTME: <pre><p>Since it&#39;s templates, use a tool that will pack your templates as strings in your source code. Then your code will always know where to find the templates: as variables in the program.</p> <p>I made a tool that works well with <code>go generate</code>:</p> <ul> <li><a href="https://github.com/aybabtme/embed" rel="nofollow">github.com/aybabtme/embed</a> (attention, ugly code)</li> </ul> <p>Here&#39;s <a href="https://github.com/aybabtme/datagen/blob/master/cmd/datagen/templates.go" rel="nofollow">an example usage of it</a>, for packing templates into a CLI tool.</p> <p>Otherwise there&#39;s also <code>go-bindata</code> which I dislike for the output is <a href="https://raw.githubusercontent.com/aybabtme/tweet-sentiments/master/bindata.go" rel="nofollow">pretty ugly code</a> and makes golint cry.</p> <ul> <li><a href="https://github.com/jteeuwen/go-bindata" rel="nofollow">github.com/jteeuwen/go-bindata</a></li> </ul> <p>So that&#39;s the solution to your problems.</p> <p>For the problem you thought you had (configuration) but don&#39;t actually have: use environment variables, or package <code>flag</code>, to configure your app. Config files are super painful for 1000x of reasons.</p></pre>pollodeldiablo: <pre><p>Thanks. I think this is the best option for native compatibility for all OSs since it doesn&#39;t require installation or any kind of file paths. Was put of since the templates are more code than the actual, but given the size of Go binaries it won&#39;t make a big difference when compiled. </p></pre>emadera52: <pre><p>I&#39;m probably missing something (common) and I&#39;m learning Go myself. I don&#39;t have time to test this tonight, so I&#39;ll just toss it out there.</p> <p>It sounds like the templates are always in the same relative place. For the sake of example, call it &#34;src/project/templates&#34; where project is your project directory. In that directory create a package file, call it &#34;templates.go&#34; that defines &#34;package templates&#34;. In that package define and export whatever config values you need. Import that package in &#34;main&#34; and anywhere else the config values are needed.</p></pre>Streamweaver66: <pre><p>Generally I include a json config file at the same directory level as the binary. I will usually check for existence at start-up and error/exit if it doesn&#39;t&#39; exist or is improperly configured. In some apps I include a command line option to generate a sample file.</p> <p>I haven&#39;t treed the ENV route because I wasn&#39;t sure how that works in relation to cross OS issues. It probably works fine but I didn&#39;t read up on it and I prefer a local JSON file because it&#39;s obvious where the config file is and there are no hidden config values (i.e. is it global, is it local to the user, bash_rc vs bash_profile etc)</p></pre>anoobisus: <pre><p>lol, why would you look in GOPATH, and not in the dir of the currently running executable?</p> <p>Why do people make things so difficult. Just pass it as a command line arg to your app. NO ONE that uses your app will be impressed with this &#34;feature&#34;... they&#39;ll be annoyed because they can&#39;t just pass it as an arg to your app./</p></pre>perihelion9: <pre><p>When running headlessly, it&#39;s a horrible pattern to keep config in the binary directory. You&#39;d clutter the hell out of /usr/bin at that point. If anything configuration ought to be under /opt or /etc.</p></pre>anoobisus: <pre><p>lmao, who the hell installs their app binary to /usr/bin?</p> <p>The whole damn thing just goes in /opt/&lt;my-project-name&gt; for the containers they run in.</p> <p>Seriously, if you&#39;re going to fuck with the unix system FS, then use a damn package. Otherwise, vendor it in /opt and keep it together. The notion that going and shoving binaries and config files into a system with using dpkg/pacman/etc is just silly nonsense.</p> <p>I mean, the best approach is to just put it in a fucking container, because then who gives a shit how it&#39;s implemented.</p></pre>intermernet: <pre><p>Woah there! You&#39;re making yourself look pretty silly here.</p> <p>People &#34;fuck with the unix system FS&#34; all the time <em>if they know what they&#39;re doing!</em> There are standards that define where configs go, where binaries go etc. How do you think package maintainers know where to put things?</p> <p>Don&#39;t go ranting with your &#34;lol&#34;s , &#34;lmao&#34;s and &#34;silly nonsense&#34;; Go do some research into the standard structure of the &#34;unix system FS&#34; (which, by the way, varies between versions, vendors, historic branches etc. and has led to some very heated discussions and debates).</p></pre>anoobisus: <pre><p>And? If you&#39;re distributing your app to production servers and not using containers, you should be packaging.</p> <p>You can disagree, but you&#39;re wrong. You&#39;d probably also tell me about how Puppet and Chef are the greatest things in the world, and that Docker and Kubernetes are &#34;stupid, because who would need that&#34;. And yeah, I&#39;ve been there and done that and I know how to do things correctly now. But thanks for all the condescension from everyone around here who got standardized on deployment practices 10 years ago and haven&#39;t bothered getting with the times.</p> <blockquote> <p>Go do some research into the standard structure of the &#34;unix system FS&#34; (which, by the way, varies between versions, vendors, historic branches etc. and has led to some very heated discussions and debates).</p> </blockquote> <p>I&#39;m well aware of this and don&#39;t see how it&#39;s relevant at all. In fact, having a package that conforms to one system, actually allows for more portable translation of that package to other environments via existing tooling. So again, not sure how that point serves anything.</p></pre>intermernet: <pre><p>Um, I&#39;m currently writing an entire application stack using Docker and Kubernetes.</p> <p>Kubernetes themselves use Salt for most of their low level OS customization, and they certainly don&#39;t store everything in /opt .</p> <p>Container deployment practices don&#39;t replace OS package deployment practices. They&#39;re different, for many reasons.</p></pre>perihelion9: <pre><blockquote> <p>The whole damn thing just goes in /opt/&lt;my-project-name&gt; for the containers they run in.</p> </blockquote> <p>I don&#39;t see anything saying he&#39;s using containers. And anyway most of the world doesn&#39;t use containers, so it&#39;s not like that&#39;s a common pattern that you can look down upon for not using.</p> <blockquote> <p>Seriously, if you&#39;re going to fuck with the unix system FS, then use a damn package.</p> </blockquote> <p>Do you really think nobody used a Unix-like FS as it was intended before package managers came along? /etc, /usr/bin, /opt, /var, etc all predate package managers. And plenty of systems are deployed, configured, and maintained without package managers. You don&#39;t need to use apt to deploy an init script and binary.</p></pre>DavidDavidsonsGhost: <pre><p>Config files should be in the working directory, it will allow the executable to be placed and called from anywhere.</p></pre>perihelion9: <pre><p>Configuration must be separate from binary - because it leaves a very consistent structure for where to find things. Logs are in <code>/var/log</code>, configuration in <code>/etc</code>, binary in <code>/usr</code>, etc. This structure means that no matter what your service is, or in what format it logs, or where you deploy it, will always act the same as all the other services. It gives predictability to anyone else using, maintaining, or operating your binary. It&#39;s easy to jump onto a box and immediately understand what it can do, how it goes about doing it, and what it&#39;s been doing just by looking in a small amount of predictable locations.</p> <p>It also makes it easier to permission the different bits. You should want configuration to be editable by anyone, logs to be readable by anyone, and the binary should only ever be writable by people with deploy privileges. Throwing everything in one directory means that whomever owns the directory owns everything; a pretty large code smell / deployment fiasco / security risk.</p> <p>Finally, It gives you the freedom to size partitions as required - since your data and logs (which are ever-growing) don&#39;t sit on the same partition as your binary (which is hopefully static). </p> <p>If your goal is an executable that isn&#39;t dependent on any other files, you ought to be espousing <em>flags</em> (which can optionally be controlled by the init script). And if you want something that is operated by users who can&#39;t be expected to know any of the above, you should be encouraging a gui.</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

892 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传