Repository navigation
ARTEMIS-6261 Add the option to run artemis as a systemd service #6714
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,6 +21,8 @@ | |
| import java.io.IOException; | ||
| import java.io.PrintWriter; | ||
| import java.io.StringWriter; | ||
| import java.nio.file.FileAlreadyExistsException; | ||
| import java.nio.file.Files; | ||
| import java.text.DecimalFormat; | ||
| import java.util.HashMap; | ||
| import java.util.LinkedHashMap; | ||
|
|
@@ -81,6 +83,8 @@ public class Create extends InstallAbstract { | |
| public static final String BIN_ARTEMIS = "bin/" + ARTEMIS; | ||
| public static final String ARTEMIS_SERVICE = "artemis-service"; | ||
| public static final String BIN_ARTEMIS_SERVICE = "bin/" + ARTEMIS_SERVICE; | ||
| public static final String ARTEMIS_SERVICE_SYSTEMD = "artemis.service"; | ||
| public static final String ETC_ARTEMIS_SERVICE_SYSTEMD = "etc/" + ARTEMIS_SERVICE_SYSTEMD; | ||
| public static final String ETC_ARTEMIS_PROFILE = "artemis.profile"; | ||
| public static final String ETC_ARTEMIS_UTILITY_PROFILE = "artemis-utility.profile"; | ||
| public static final String ETC_LOG4J2_PROPERTIES = "log4j2.properties"; | ||
|
|
@@ -340,6 +344,12 @@ public String[] getStaticNodes() { | |
| @Option(names = "--jdbc-lock-expiration", description = "Lock expiration (in milliseconds).") | ||
| long jdbcLockExpiration = ActiveMQDefaultConfiguration.getDefaultJdbcLockExpirationMillis(); | ||
|
|
||
| @Option(names = "--enable-systemd-service", description = "Enable systemd service. Default is false.") | ||
| boolean enableSystemdService = false; | ||
|
|
||
| @Option(names = "--systemd-service-name", description = "Name of the artemis systemd service. Default is 'artemis'.") | ||
| String systemdServiceName = "artemis"; | ||
|
|
||
| private boolean isAutoCreate() { | ||
| if (autoCreate == null) { | ||
| if (noAutoCreate != null) { | ||
|
|
@@ -573,6 +583,68 @@ private boolean isDisablePersistence() { | |
| return disablePersistence; | ||
| } | ||
|
|
||
| public void setSystemdServiceInstall(boolean enableSystemdService) { | ||
| this.enableSystemdService = enableSystemdService; | ||
| } | ||
|
|
||
| public void generateSystemdService(File etcFolder) throws Exception { | ||
| Map<String, String> serviceFilters = new LinkedHashMap<>(); | ||
|
|
||
| // set JAVA_ARGS_APPEND: Set console output level to OFF when runing as a service. Output to logs only. | ||
| serviceFilters.put("${java-args-append}", "JAVA_ARGS_APPEND=-Dartemis.console.level=OFF"); | ||
| // set the ARTEMIS_INSTANCE environment variable and the exec-start command to run the broker | ||
| serviceFilters.put("${environment}", "ARTEMIS_INSTANCE=" + path(directory)); | ||
| serviceFilters.put("${exec-start}", path(directory) + "/bin/artemis run"); | ||
|
|
||
| write(ETC_ARTEMIS_SERVICE_SYSTEMD, new File(etcFolder, systemdServiceName + ".service"), serviceFilters, true, false); | ||
| } | ||
|
|
||
| public void enableSystemdService() throws Exception { | ||
|
|
||
| if (enableSystemdService) { | ||
| File systemdServiceFile = new File(directory, "etc/" + systemdServiceName + ".service"); | ||
| File targetServiceFile = new File("/etc/systemd/system/" + systemdServiceName + ".service"); | ||
|
|
||
| try { // try enabling the service automatically | ||
| Files.copy(systemdServiceFile.toPath(), targetServiceFile.toPath()); | ||
| getActionContext().out.println("Executing systemctl daemon-reload && systemctl enable " + systemdServiceName + ".service ..."); | ||
| executeCommand("systemctl", "daemon-reload"); | ||
| executeCommand("systemctl", "enable", systemdServiceName + ".service"); | ||
|
Comment on lines
+611
to
+612
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not in favor of having the Artemis CLI execute commands like this. Folks familiar with systemd will know how this works and will either do it manually or via a script. We can just document it for folks who are not familiar. |
||
|
|
||
| getActionContext().out.println("Systemd unit file was generated and enabled at:"); | ||
| getActionContext().out.println(String.format(" /etc/systemd/system/%s.service", systemdServiceName)); | ||
| getActionContext().out.println(); | ||
| getActionContext().out.println("To start it, execute:"); | ||
| getActionContext().out.println(String.format(" systemctl start %s.service", systemdServiceName)); | ||
| } catch (FileAlreadyExistsException e) { | ||
| getActionContext().out.println("Service file already exists at " + targetServiceFile.getAbsolutePath() + "."); | ||
| } catch (Exception e) { | ||
| getActionContext().out.println("Unable to install service: " + e.getMessage()); | ||
| } | ||
| } else { // print out instructions to enable the service | ||
| getActionContext().out.println("Systemd unit file was generated at:"); | ||
| getActionContext().out.println(String.format(" \"%s\"", path(new File(directory, "etc/" + systemdServiceName + ".service")))); | ||
| getActionContext().out.println(); | ||
| getActionContext().out.println("To enable it, run this as root or with sudo privileges:"); | ||
| getActionContext().out.println(String.format(" cp \"%s\" /etc/systemd/system/%s.service", path(new File(directory, "etc/" + systemdServiceName + ".service")), systemdServiceName)); | ||
| getActionContext().out.println(String.format(" systemctl daemon-reload && systemctl enable %s.service", systemdServiceName)); | ||
| } | ||
| } | ||
|
|
||
| private void executeCommand(String... command) throws Exception { | ||
| ProcessBuilder pb = new ProcessBuilder(command); | ||
| pb.redirectErrorStream(true); | ||
| Process process = pb.start(); | ||
|
|
||
| String output = new String(process.getInputStream().readAllBytes()).trim(); | ||
| int exitCode = process.waitFor(); | ||
|
|
||
| if (exitCode != 0) { | ||
| throw new RuntimeException(String.format("Command '%s' failed with exit code %d: %s", | ||
| String.join(" ", command), exitCode, output)); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public Object execute(ActionContext context) throws Exception { | ||
| this.checkDirectory(); | ||
|
|
@@ -796,7 +868,6 @@ public Object run(ActionContext context) throws Exception { | |
|
|
||
| boolean allowAnonymous = isAllowAnonymous(); | ||
|
|
||
|
|
||
| String retentionTag; | ||
| if (retentionDays > 0) { | ||
| if (retentionMaxBytes != null) { | ||
|
|
@@ -927,6 +998,11 @@ public Object run(ActionContext context) throws Exception { | |
| } | ||
| writeEtc(ETC_JOLOKIA_ACCESS_XML, etcFolder, filters, false); | ||
|
|
||
| generateSystemdService(etcFolder); | ||
| if (IS_NIX) { | ||
| enableSystemdService(); | ||
| } | ||
|
|
||
| context.out.println(""); | ||
| context.out.println("You can now start the broker by executing: "); | ||
| context.out.println(""); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| # Licensed to the Apache Software Foundation (ASF) under one | ||
| # or more contributor license agreements. See the NOTICE file | ||
| # distributed with this work for additional information | ||
| # regarding copyright ownership. The ASF licenses this file | ||
| # to you under the Apache License, Version 2.0 (the | ||
| # "License"); you may not use this file except in compliance | ||
| # with the License. You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, | ||
| # software distributed under the License is distributed on an | ||
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| # KIND, either express or implied. See the License for the | ||
| # specific language governing permissions and limitations | ||
| # under the License. | ||
|
|
||
| [Unit] | ||
| Description=Apache Artemis Service | ||
| After=network-online.target | ||
| Wants=network-online.target | ||
|
|
||
| [Service] | ||
| Type=exec | ||
| Environment=${environment} | ||
| Environment=${java-args-append} | ||
| ExecStart=${exec-start} | ||
| TimeoutStopSec=60s | ||
| SuccessExitStatus=143 | ||
| KillMode=mixed | ||
| LimitMEMLOCK=infinity | ||
| LimitNOFILE=524288 | ||
| LimitNPROC=31438 | ||
| LimitAS=infinity | ||
| LimitFSIZE=infinity | ||
| SendSIGKILL=no | ||
| NotifyAccess=all | ||
| Restart=always | ||
| RestartSec=10 | ||
| #User=artemis | ||
| #Group=artemis | ||
|
|
||
| [Install] | ||
| WantedBy=multi-user.target |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| = Systemd | ||
| :idprefix: | ||
| :idseparator: - | ||
| :docinfo: shared | ||
|
|
||
| == Automatic systemd service generation | ||
|
|
||
| A systemd service file is generated automatically when you create the broker via cli. The file is available at `pathToBrokerInstance/etc/artemis.service`. | ||
|
|
||
| The contents of the automatically generated file look like this: | ||
|
|
||
| [,console] | ||
|
|
||
| ---- | ||
| [Unit] | ||
| Description=Apache Artemis Service | ||
| After=network.target network-online.target | ||
| Wants=network-online.target | ||
|
|
||
| [Service] | ||
| Type=exec | ||
| Environment=ARTEMIS_INSTANCE=/pathToBrokerInstance | ||
| Environment=JAVA_ARGS_APPEND=-Dartemis.console.level=OFF | ||
| ExecStart=/pathToBrokerInstance/bin/artemis run | ||
| TimeoutStopSec=60s | ||
| SuccessExitStatus=143 | ||
| KillMode=mixed | ||
| LimitMEMLOCK=infinity | ||
| LimitNOFILE=524288 | ||
| LimitNPROC=31438 | ||
| LimitAS=infinity | ||
| LimitFSIZE=infinity | ||
| SendSIGKILL=no | ||
| NotifyAccess=all | ||
| Restart=always | ||
| RestartSec=10 | ||
| #User=artemis | ||
| #Group=artemis | ||
|
|
||
| [Install] | ||
| WantedBy=multi-user.target | ||
| ---- | ||
|
Comment on lines
+10
to
+33
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Repeating the contents of the file here is going to create a maintenance burden. I recommend simply referencing the file so users can find the content of the file directly themselves. |
||
|
|
||
| You might want to tweak or add additional configuration inside the service file, for example: | ||
|
|
||
| * uncomment and/or change `User` with which to run the service, to avoid running as root | ||
| * add `Nice` to tweak niceness of the java process | ||
| * add `Alias` | ||
| * increase or decrease `TimeoutStopSec` and `RestartSec` | ||
| * tweak the console log level, which is set to `OFF` to avoid the overhead of logging to both file and console | ||
|
Comment on lines
+35
to
+41
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These might be better as comments in the service file itself. |
||
|
|
||
| You can read more about systemd https://systemd.io/[here]. | ||
|
|
||
| == Enable systemd service via flags | ||
|
|
||
| It is also possible to automate the service installation via `--enable-systemd-service` and `--systemd-service-name` flags. | ||
| In order to do this, the broker creation script usually needs to be run with `sudo` or `root` privileges. | ||
|
|
||
| To enable the service automatically, and to change its name (from the default `artemis`), run: | ||
|
|
||
| `./artemis create brokername --enable-systemd-service --systemd-service-name=artemisTest` | ||
|
|
||
| You can now use `systemctl` commands to start/stop/restart the service, named `artemisTest`: | ||
|
|
||
| [,console] | ||
| ---- | ||
| systemctl start artemisTest | ||
| systemctl stop artemisTest | ||
| systemctl restart artemisTest | ||
| ---- | ||
|
|
||
| You can read the systemctl man page https://man7.org/linux/man-pages/man1/systemctl.1.html[here]. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,14 @@ NOTE: Follow the general upgrade procedure outlined in the xref:upgrading.adoc#u | |
| * AMQP message size estimation has been improved to account for the full message metadata, fixing underestimates that occurred when messages carried large application properties. | ||
| * AMQP broker connection Senders, Receivers and Peer configurations have been deprecated and will be removed in a future release. | ||
| Users of the AMQP broker connection Senders and Receivers are encouraged to migrate to the newer AMQP Bridge configurations that provide more robust and configurable send to and receive from topologies. | ||
| * https://issues.apache.org/jira/browse/ARTEMIS-6261[ARTEMIS-6261] - Run artemis as a systemd service | ||
| Automated systemd unit file generation has been added to the broker instance creation tool. | ||
| The service is not enabled by default. | ||
| If running the creation script with `sudo` or `root` privileges, you can pass `--enable-systemd-service` to automatically enable the service at system startup. | ||
| The service file will then be placed in `/etc/systemd/system` and the commands `systemctl daemon-reload` and `systemctl enable artemis.service` will be executed automatically. | ||
| To customize the unit name use the `--systemd-service-name` flag (e.g., `--systemd-service-name=artemis-broker`). | ||
| The service can then be started/stopped by using commands like `systemctl start/stop artemis`. | ||
| This native systemd integration is preferred over the legacy `artemis-service` script. | ||
|
Comment on lines
+27
to
+34
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Highlights here should be short and sweet. Details should be available via hyperlinks for users who want more info. |
||
|
|
||
| === Upgrading from 2.57.0 | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this preclude using
journalctlwhich is standard practice for services managed by systemd? It seems like if folks want to manage the broker via systemd then the file log should be disabled instead of the console log so they can usejournalctland all the features it provides without duplicate logging.