Como executo um único comando na inicialização usando o systemd?

113

Gostaria de inicializar um cluster do Apache Spark após a inicialização usando o seguinte comando:

sudo ./path/to/spark/sbin/start-all.sh

Em seguida, execute este comando quando o sistema se preparar para reiniciar / desligar:

sudo ./path/to/spark/sbin/stop-all.sh

Como posso começar? Existe um modelo básico no qual eu possa construir?

Eu tentei usar um extremamente simples (arquivo /lib/systemd/system/spark.service:):

[Unit]
Description=Spark service

[Service]
ExecStart=sudo ./path/to/spark/sbin/start-all.sh

O que não funciona.

macourtney7
fonte
Oi @WillemK, eu já tinha consultado esta página. Esta questão que eu encontrei é que eu não pode simplesmente substituir execcom ExecStart=. Além disso, eu não usei o iniciante antes.
macourtney7
11
O ponto antes do caminho do seu script parece extremamente suspeito.
Andrea Lazzarotto
@AndreaLazzarotto Eu acho que OP está tentando executar o script a maneira OP faria no terminal daí o ....
George Udosen
Olá @AndreaLazzarotto, está correto. Desculpas por qualquer confusão causada.
macourtney7

Respostas:

144

Seu .servicearquivo deve ficar assim:

[Unit]
Description=Spark service

[Service]
ExecStart=/path/to/spark/sbin/start-all.sh

[Install]
WantedBy=multi-user.target

Agora, execute mais algumas etapas para ativar e usar o .servicearquivo:

  1. Coloque-o na /lib/systemd/systempasta com, digamos, um nome demyfirst.service

  2. Faça com que seu script seja executável com:

    chmod u+x /path/to/spark/sbin/start-all.sh
    
  3. Inicie:

    sudo systemctl start myfirst
    
  4. Permita que ele seja executado na inicialização:

    sudo systemctl enable myfirst
    
  5. Pare com isso:

    sudo systemctl stop myfirst
    

Notas:

  1. Você não precisa iniciar o Spark com sudo no seu serviço, pois o usuário padrão do serviço já é root.

  2. Veja os links abaixo para mais systemdopções.

ATUALIZAR

Agora, o que temos acima é apenas rudimentar, aqui está uma configuração completa do Spark:

[Unit]
Description=Apache Spark Master and Slave Servers
After=network.target
After=systemd-user-sessions.service
After=network-online.target

[Service]
User=spark
Type=forking
ExecStart=/opt/spark-1.6.1-bin-hadoop2.6/sbin/start-all.sh
ExecStop=/opt/spark-1.6.1-bin-hadoop2.6/sbin/stop-all.sh
TimeoutSec=30
Restart=on-failure
RestartSec=30
StartLimitInterval=350
StartLimitBurst=10

[Install]
WantedBy=multi-user.target

Para configurar o serviço:

sudo systemctl start spark.service
sudo systemctl stop spark.service
sudo systemctl enable spark.service

Leitura adicional

Por favor, leia os seguintes links. O Spark é uma configuração complexa, portanto você deve entender como ele se integra ao serviço init do Ubuntu.

https://datasciencenovice.wordpress.com/2016/11/30/spark-stand-alone-cluster-as-a-systemd-service-ubuntu-16-04centos-7/

https://www.digitalocean.com/community/tutorials/understanding-systemd-units-and-unit-files

https://www.freedesktop.org/software/systemd/man/systemd.unit.html

George Udosen
fonte
Anotado e atualizado
George Udosen 26/17
11
Obrigado por isso, criei um arquivo com base no que você sugeriu. Ao executar sudo systemctl start sparké receber o seguinte erro:Failed to start spark.service: Unit spark.service is not loaded properly: Invalid argument. See system logs and 'systemctl status spark.service' for details.
macourtney7
A parte principal do systemctl status spark.serviceé a seguinte: Executable path is not absoluteespark.service: Service lacks both ExecStart= and ExecStop= setting. Refusing.
macourtney7
Os problemas são: 1) o caminho binário do Spark (deve substituir o que temos no arquivo de serviço) é necessário; 2) o Spark possui um comando de desligamento. 3) Você passou pelos links que eu lhe dei. Não uso faísca assim fornecê-los
George Udosen
@GeorgeUdosen Obrigado pela sua resposta, minha pergunta é como executar o spark sob um comando específico após a reinicialização? A questão está aqui askubuntu.com/questions/979498/…
Soheil Pourbafrani
2

Isso cria e executa /root/boot.shna inicialização (como raiz) usando um arquivo de serviço mínimo:

bootscript=/root/boot.sh
servicename=customboot

cat > $bootscript <<EOF
#!/usr/bin/env bash
echo "$bootscript ran at $(date)!" > /tmp/it-works
EOF

chmod +x $bootscript

cat > /etc/systemd/system/$servicename.service <<EOF
[Service]
ExecStart=$bootscript
[Install]
WantedBy=default.target
EOF

systemctl enable $servicename

Você pode Ctrl+ Cisso em um terminal raiz.

Para modificar os parâmetros, por exemplo, para usar um diferente $bootscript, defina essa variável manualmente e apenas pule essa linha ao copiar os comandos.

Após executar os comandos, você pode editar o script de inicialização usando o seu editor favorito, e ele será executado na próxima inicialização. Você também pode executá-lo imediatamente usando:

systemctl start $servicename

Todas as etapas podem ser feitas com o sudo, mas são um pouco mais complicadas, e alguns sistemas não têm o sudo instalado; portanto, algumas pessoas precisam modificar o exemplo antes do uso. Portanto, eu escolhi não incluir o sudo no exemplo.

Luc
fonte
Estou um pouco confuso com os documentos do systemd, mas não deveria ser Type=oneshot RemainAfterExit=yesou o systemd considerará a tarefa inativa, a menos que o script personalizado deixe alguns processos em execução.
Peter Lamberg
@ PeterLamberg Também tentei ler os documentos do systemd e, no entanto, aqui estamos nós;). Lembro que eles não eram muito claros, mas a resposta que publiquei funciona para mim em vários sistemas (revisito esta página de vez em quando quando preciso novamente). Você quer dizer que, por ser considerado "inativo", toda chamada de "início" sucessiva executará novamente o script? Porque eu consideraria isso como esperado para um script de shell. Eu acharia estranho se eu tivesse que 'parar' algo que não está realmente funcionando antes que eu possa iniciá-lo novamente.
Luc