Tagged: systemd

Systemd 유닛, 부팅 후 5분 후에 실행시키기

간혹 이런게 필요할때가 있다. 부팅을 하고 난 후에, 그것도 한 10분 후 혹은 5분 후에 프로그램을 한번만 실행시키고 싶을때…. 보통 이런 것들은 시스템 모니터링을 위해 시스템의 정보를 원격 서버에 등록하는 것과 같은 것이 있다.

과거에는 /etc/rc.local 에 스크립트를 등록해서 해결했다. 하지만 rc.local 도 SystemV Init 의 유산이라, Systemd 로 변경되면서 사라졌다.

그러면 부팅 후 실행 혹은 부팅하고 5분, 수분, 그러니까 몇분이 지난 후에 한번 실행시키는 방법은 없을까?

Systemd Timer

Systemd 는 Timer 라는 게 있다. Systemd 유닛에 여러 타입이 있는데, 일반적으로 service 를 타입을 많이 쓴다. service 타입은 그야말로 데몬으로 등록하도록하는 것이다. Spring Boot 를 시작/중지 시키기등을 할때에 service 유닛을 만든다.

Timer 는 이름에서와 같이 시간에 의존해서 작동된다. 놀랍게도 timer 유닛은 오랫동안 그리고 현재도 리눅스에 사용되고 있는 cron 을 대체할 수도 있다.

특정 시점에서 실행시키기도 하고 몇분마다 반복적으로 실행되게 할 수도 있다. 아예 날짜를 지정해 특정 날짜가 되면 실행이되도록 할 수도 있다. 서론에서 말했던 부팅하고 난 후에 몇분 후에 실행되도록 할 수도 있다.

timer 유닛은 이름 그대로 시간만 잰다. timer 유닛은 유닛 이름과 동일한 service 유닛을 설정된 시간에 실행시켜주는 역할만 한다. 그래서 timer 유닛은 동일한 service 유닛과 함께 사용된다.

그러면 ‘부팅을 한 후 5분 후에 service 유닛을 실행시키기’ 를 한번 해보자.

‘한번만 실행된다’ 주목해서 service 유닛에서 실행 타입을 ‘oneshot’ 으로 해줘야 한다. 다음 예제와 같다.

이름은 간단하게 ‘a.service’ 로 했다. service 유닛의 위치는 /etc/systemd/system 디렉토리다. 이제 service 유닛을 부팅 후에 5분이 된 시점에 실행되도록 timer 유닛을 다음과 같이 작성한다. 파일 이름은 a.timer 다.

단순하다. 중요한건 유닛의 이름이 같아야 한다.

주의사항

한가지 주의사항이 있다. service 유닛을 timer 유닛이 실행시켜주는 구조로 되어 있다보니 service 유닛은 ‘enabled’ 상태여서는 안된다. enabled 상태란, 부팅과 동시에 자동 실행 설정이다. 그런데, timer 유닛은 특정 시점에서 service 유닛을 실행시켜야 하기 때문에 service 유닛이 부팅과 동시에 자동으로 실행되면 안된다.

따라서, service 유닛은 ‘disabled’ 상태여야 하고 timer 유닛은 ‘enabled’ 상태여야 한다.

Timer 유닛 리스트, 상태

timer 유닛에 어떤게 있는지를 다음과 같이 확인할 수 있다.

timer 유닛에 스케줄 상태를 다음과 같이 확인할 수있다.

몇가지 예제

다음과 같은 예제가 있다.

위 설정은 부팅 후 5분후에 처음 실행되고, 이부터는 1시간 간격으로 실행된다.

참고

create a systemd startup script that delays 30 minutescreate a systemd startup script that delays 30 minutes

Spring boot 에 systemd 유닛 만들기

요즘 프로젝트를 하고 있는데, 역시나 자바 시스템이 있다. Spring Boot3 을 사용하고 있고 자바 17을 쓰는등 나름대로 괜찮은 환경에서 개발이 이루어지고 있다. 그런데, 이것을 서버에서 배포를 하고 Spring Boot 를 실행해야 하는데, 어떻게 하나 봤더니 초보자 수준도 못 벗어나는 설정을 하고 있으니… 안타까운 마음에 어떻게 하는 것이 좋은 것인지 한번 적어봤다.

Spring boot, jar 실행 파일

Spring Boot3 를 컴파일 하면 jar 파일 나온다. 그리고 별다른 서버 없이도 바로 실행하고 접속이 가능해 진다. 한가지 재미있는 사실은 많은 사람들이 Spring boot3 에 실행 파일 jar 이 내장된 WAS 서버가 구동되면서 실행된다는 걸 모른다는 거다. 심지여 그것이 Tomcat 이라는 것도. 물론 어떤 프로그래밍 모델인지에 따라서 Tomcat 이 되기도 하고 Netty 되기도 하지만, 과연 Reactive Programming Model 로 짜는 사람이 몇이나 있나 싶다. 대부분 Spring MVC 이고 Servlet 이면 기본적으로 Tomcat 이 구동된다. 내장형 Tomcat

프로젝트에서 쓰는 방법

현재 프로젝트에서는 jar 실행을 위해서 스크립트 파일을 만들었다. 대략 다음과 같다.

자바 옵션인 -D 옵션과 jar 실행 파일을 인자로 주고 있다. 그런데, 특이하게도 데몬화를 하지 않았고 많은 초보자식 설정인 nohup 도 없다. 이렇게되면 프로그램이 포그라운드(Foreground) 실행이되어서 쉘이 묶이게 된다.

어떻게 했지? 봤더니 systemd 에 이 실행파일을 넣고 systemd 를 통해서 시작/중지를 하고 있었다. 다음과 같다.

‘ExecStart=’ 에 쉘 스크립트 실행 파일을 지정해 주고 있다.

왜 이렇게 해야 하나? 왜? 이해 할 수 없는 구조다.

Spring 공식 문서

Systemd 유닛에 등록하는 방법은 Spring 공식문서에도 나와 있다.

57.1.2 Installation as a systemd service

이 문서에 나온 systemd 유닛 파일은 프로젝트 유닛 파일과 다르다. 공식 문서에 내용은 그냥 아주 기초적인 내용만 적혀 있다. 실제 프로젝트에 적용하기에는 무리가 있다.

설정파일 작성

Spring boot 를 위한 설정을 systemd 유닛에서 사용할 수 있는 별도의 파일로 작성한다. 이 설정은 JAVA_OPTS 의 내용을 담으면 된다.

이것을 이제 systemd 에서 사용하면 다음과 같다.

공식문서에 나와 있는 내용과 EnvironmentFile 속성으로 외부에서 JAVA_OPTS 를 지정한 내용을 읽어오도록 하면 충분히 사용가능해 진다.

프로젝트에서 처럼 스크립트로 한번 감싸고 이것을 다시 systemd 유닛에서 실행되도록 할 필요가 없다는 것이다.

몇가지 개선 설정

공식문서는 간단한 예이다. 실행이 가능한 정도의 유닛 파일일 뿐이다. systemd 를 이용해 자바 애플리케이션을 실행할 때에는 여러가지를 고려해야 한다.

일단 자바 애플리케이션은 네트워크를 기반으로 한다. 따라서 네트워크 온라인 상태여야 한다. 또, StdOut, StdErr 를 Journal 로 내보내도록 해야 한다.

systemd unit 편집기 바꾸기

systemd 는 이제 리눅스 시스템의 뼈대가 되는 기본운영 방법이 되었다. 기존에는 System V Init 이였지만 RHEL 7, Ubuntu 16.04부터 기본 시스템운영 프로그램이 되었다.

systemd 는 ‘ctl’ 로 끝나는 명령어들의 집합으로 제어가 가능하다. systemctl, journalctl, timedatectl, hostnamectl, loginctl 이 대표적이다. systemctl 의 경우에는 systemd unit 파일들에 대한 제어와 설정이 가능하다. systemd unit 파일은 기존의 Systemv V init Script 를 대체하는 것으로 일종의 시스템 데몬 프로그램들이라고 보면 된다. 시스템이 시작될때에 자동으로 시작되게 한다거나 종료하게 한다거나 하는것들을 가능하게 한다.

unit 파일은 텍스트 파일이기 때문에 언제든지 파일을 열어서 편한대로 편집이 가능한데, systemctl 명령어는 이런 unit 파일에 대한 편집기능을 제공 한다. unit 파일이 있는 곳으로 가서 텍스트 편집기를 열 필요가 없이 systemctl edit –full 명령어를 이용하면 가능하다.

문제는 systemctl edit — full 명령어를 입력했을 때에 실행되는 에디터가 nano 로 열리는 경우가 많은데, 이것을 바꿀 수 있다.

다음의 내용은 다음의 링크 내용을 정리한 것이다.

SYSTEMD_EDITOR 환경변수 설정

제일 쉬운 방법은 SYSTEMD_EDITOR 환경변수 설정이다. 대부분 Bash 를 사용하기 때문에 이것을 다음과 같이 쉘 환경변수로 설정 해준다.

매번 로그인 할때마다 입력하기 귀찮으면 ~/.bashrc 파일에 추가해주면 로그인할때마다 자동 적용된다.

만일 일반계정으로 로그인을 하고 sudo systemctl edit –full 명령어를 이용한다면 /etc/sudoers 파일에 다음을 추가해 줘야 한다.

sudo 를 실행하는 계정에 있는 환경 변수인 SYSTEMD_EDITOR 를 유지하라는 뜻이다.

update-alternatives 로 기본 에디터 변경

update-alternatives 는 alternative 가 가능한 여러 명령어들을 바꿔 주는 기능을 한다. 이것은 매우 유용한데, 예를들어 Python3 관련 버전이 여려개일 경우에 python3 에 기본 버전을 시스템적으로 지정해 줄 수 있다. update-alternatives –list 명령어를 입력하면 현재 등록된 대체가능한 명령어들이 보인다.

리눅스에서 편집기는 editor 라는 명령어로 되어 있고, 정확하게는 심볼릭 링크다, 이것을 update-alternatives 명령어로 바꿔주면 된다.

위에 내용을 보면 기본 에디터로 nano 가 설정되었다고 나온다. 이것을 바꿔주면 시스템적으로 기본 에디터가 변경되게 된다.

EDITOR 환경변수 지정

실행할때에마다 EDITOR 환경변수를 다음과 같이 지정해주면 된다.

Ubuntu, systemd-networkd 전환하기

Ubuntu 16.04 로 넘어오면서 SysV 의 Init 이 Systemd 로 변경되었다. 이런 변화에는 Network 관리에도 적용되고 있는데, 이에 대해서 알아보자.

기존의 Network 관련된, 정확하게는 Network Interface 와 관련된 일은 NetworkManager 가 담당했다. Network Interface 가 무엇인지, 아이피는 DHCP 혹은 Static 인지 등이 그것이다.

하지만 Ubuntu 16.04 로 넘어오면서 시스템에 관련된 일체가 systemd 로 통합되면서 네트워크 관련 작업도 systemd 로 통합되어지게 되는데, 이것이 systemd-networkd 이 이다.

하지만 Ubuntu 18.04 로 넘어온 시점에서도 NetworkManger 는 이전과 호환을 위해서 살려뒀고 살려둔김에 지금도 기본적인 네트워크 설정 프로그램으로 활약(?) 하고 있다.

Network Manager

Network Manager 의 동작은 다음의 명령어로 이루어진다.

관련 설정은 /etc/NetworkManger/NetworkManger.conf 파일이다. 위 프로그램을 실행하게 되면 기본적으로 이 파일을 읽게 되어 있다.

그리고 netplan 설정에서도 NetworkManager 를 기본으로 지정하도록 되어 있다.

Network Manager 비활성화

비활성화는 다음과 같이 하면 된다.

이렇게 하면 네트워크가 비활성화 됨으로 절대로 원격지 서버에서 하면 안된다.

systemd-networkd 활성화

netplan

systemd-networkd 를 활성화하면 이제 네트워크 작업은 netplan 명령어를 통해서 이루어진다. 이 netplan 명령어는 기본적으로 ‘/etc/netplan’ 디렉토리에 파일을 읽어서 네트워크 설정을 적용해 준다.

‘/etc/netplan’ 디렉토리에 설정파일은 기본적으로 yaml 파일형식을 가진다. 예를 들면 다음과 같다.

파일을 수정한 후에는 다음과 같이 명령어만 주면 적용이 된다.

‘–debug’ 는 제외해도 된다.

systemctl tomcat no bind 8005 port

Tomcat 을 설치하고 난후에 systemd 에 유닛으로 등록하고 나고 서비스를 시작하고 shutdown 을 하려고 할때에 다음과 같은 오류를 만날 수 있다.

8005 포트로 접속을 할 수 없어서 셧다운시에 오류를 발생시키는 것이다. 왜 이런문제가 발생할까? systemd tomcat 유닛의 내용은 다음과 같다.

그리고 이 상태로 다음과 같이 tomcat 을 서비스로 시작 한다.

이렇게 하고 난후에 netstat 명령어로 포트 리스닝 상태를 살펴보면 8005 포트가 보이지 않는다. 더 큰 문제는 shutdown 포트가 올라오지 않으면 Tomcat 이 작동하지 않는데 있다.

해결 방법은 의외로 간단하다. 다음과 같이 systemd tomcat 유닛 파일에 WorkingDirectory 를 CATALINA_BASE 로 해주면 된다.

이렇게 하게되면 tomcat 이 shutdown 포트까지 올라오면서 정상적으로 다 구동되게 된다.

ps, 이걸 몰라 3시간을 해멧다.

systemd –user 사용하기

Systemd 는 기존 리눅스 시스템에서 사용해왔던 init script 를 대체한다. 배포판마다 적용된 버전이 다른데, CentOS에 경우에는 7 버전부터 Ubuntu 의 경우에는 16.04 부터 적용되기 시작했다.

Systemd 는 부팅과정에서 최초로 실행되는 프로세스이며 리눅스 시스템 전체를 움직하게 하는 프로세스이다. 이 프로세스는 또 다른 프로세스들을 제어하는데 이를 위해서 systemd 프로그램을 제공한다.

부팅과정에서 자동으로 데몬들을 실행시키는 것도 systemd 가 하는데 이 프로그램은 데몬에 대한 명세서인 unit 파일을 기반으로 실행을 시켜준다. 이러한 파일들은 전역 시스템 영역에 속한다.

전역 systemd 영역

전역 systemd 영역의 파일들은 다음에 디렉토리를 가진다.

  • CentOS: /usr/lib/systemd
  • Ubuntu: /lib/systemd

한가지 특징이 있는데, CentOS 경우에는 전역 systemd 디렉토리가 한가지이지만 Ubuntu 의 경우에는 /lib/systemd외에 /usr/lib/systemd 도 존재하는데 /usr/lib/systemd 는 user 영역을 위한 것이다.

커스터마이징 전역 systemd 영역

앞서 살펴본 디렉토리는 배포판의 패키지를 설치할 경우에 사용되어진다. 하지만 이것외에 별도에 설치한 데몬 프로그램을 전역 systemd 에 등록하고 싶다면 다음의 디렉토리를 사용한다.

  • /etc/systemd

예를들어 컴파일 설치한 프로그램, 자바 프로그램의 경우에 systemd 에 등록해서 사용하자 한다면 위 디렉토리에 unit 파일을 작성하면 된다.

사용자 systemd 영역

systemd 는 자동으로 데몬으로 실행시켜 준다. 그런데, 이러한 실행은 systemd 라는 전역적인 권한을 가진 상태에서 이루어진다. 그렇다면 사용자가 자신만의 systemd 를 운영할 수 없지않을까 하는 아이디어로 나온것이 사용자 systemd 영역이다.

동작방법은 두가지로 나뉜다.

  • 사용자가 시스템에 로그인을 할때 실행
  • 시스템이 부팅할때에 사용자 systemd 영역도 함께 실행

그리고 사용자 systemd 영역은 사용자 홈디렉토리에 unit 파일을 작성해야 한다. 이 디렉토리는 다음의 위치에 존재한다.

  • ~/.config/systemd/user

사용자 systemd 영역 실행은 다음의 명령어를 사용한다.

  • systemctl –user

사용자 systemd 영역 동작 방법

잠깐 어떻게 이게 가능한지를 설명해 본다. 이 기본적인 동작을 위해서는 PAM 이 실행되어야 하는데 /etc/pam.d/systemd-user 파일이 이 일을 하게 해준다. 이 파일은 대략 다음과 같다.

이 PAM 모듈은 사용자가 로그인을 하게 되면 자동으로 systemd –user 명령을 실행해준다. 그리고 로그아웃을 하게되면 systemd –user 로 실행된 프로세스는 종료된다.

기본 설정

모든 사용자 systemd 영역 파일들은 ~/.config/systemd/user 에 존재하게 된다. 처음 로그인을 할때에 서비스가 실행되길 원한다면 다음과 같이 서비스를 활성화 할 수 있다.

한가지 팁(Tip) 으로, 만일 root 사용자라면 모든 시스템 사용자의 사용자 systemd 영역 서비스를 다음과 같이 할 수 있다.

환경 변수

서비스 데몬들이 실행될때에도 환경 변수들이 필요하다. 예를들어, PATH 같은 것이 대표적이다. 문제는 사용자 systemd 영역 서비스 데몬들은 .bashrc 파일에 정의된 환경변수들을 계승하지 않는다.  이것은 environment.d 디렉토리에 정의하는데 위치는 ~/.config/environment.d/ 이며 여기에 .conf 확장자를 가지는 파일을 작성하는데 INI 형식인 NAME=VAL 식으로 작성한다.

전역적인 환경변수 파일은 다음에 위치한다. 이 파일들은 모든 사용자 unit 파일에 영향을 준다.

  • /etc/environment.d/*.conf
  • /usr/lib/environment.d/*.conf
  • /etc/environment

모든 사용자 unit 에 영향을 주는 기본 환경변수인 DefaultEnvironment 는 /etc/systemd/user.conf 도 있다.

기존의 환경 변수들을 추가할 수도 있다. 예를들어, PATH 라는 환경변수는 사용자마다 가장 많이 커스터마이징되는 변수다. 이러한 변수를 systemd 에서 환경변수로 등록하고자 한다면 다음과 같이 해준다.

사용자 systemd 영역에 설정된 변수들을 보고 싶다면 다음과 같이 하면 된다.

사용자 systemd 자동 실행

systemctl –user 사용은 사용자가 로그인을 해야만 실행이되며 사용자 세션이 닫히면, 사용자가 로그아웃을 하면 자동으로 종료 된다. 하지만 사용자의 로그인/로그아웃에 상관없이 서버가 부팅되면 자동으로 실행되고 서버가 종료되어야만 중지되게 하고 싶다면 어떻게 할가?

이것은 로그인 관련된 내용으로 링거링(Lingering) 설정에 영향을 받는다.

multi-user.target 문제

systemd unit 파일 작성할때에 어떤 환경에서 실행될 것인지를 명시하기 위해서 다음과 같이 작성한다.

그런데, ‘systemctl –user’ 를 사용할때에는 multi-user.target 사용해서는 안된다. 이는 –user 에서 사용할 수 있는 타켓이 제한되어 있기 때문인데, 다음과 같이 확인이 가능하다.

위에 리스트를 보면 multi-user.target 은 존재하지 않는다. 따라서 ‘systemd –user’ 사용을 위한 systemd 유닛 파일을 작성할때에는 default.target 을 사용하는 것이 적절하다.

ElasticSearch 에 대한 systemd unit 파일 예제.

이제 간단하게 예제하나를 작성해 보자.

전문 검색 엔진인 ElasticSearch 는 자바를 기반으로 작동한다. 그러다보니 반드시 root 로 실행할 필요가 없다. 실제로 대부분 자바기반의 서비스들은 일반 계정으로 실행하는게 대부분이다.

unit 파일에 대해서 먼저 알아둘 필요가 있다. 이 파일들은 대체로 다음에 위치한다.

  • /usr/lib/systemd/systemd: 설치된 패키지에 의해서 제공된 units
  • /etc/systemd/systemd: 시스템 관리자에 의해서 제공된 units

하지만 사용자 systemd 영역을 사용할 것임으로 앞에서 언급한 대로 사용자 홈디렉토리에 관련 디렉토리를 생성해 준다.

자바 프로그램은 자바를 필요로하는데, 설치가 되어 있다고 하더라도 PATH, JAVA_HOME 등의 환경변수를 설정해 줘야 한다. systemd 가 알아차릴 환경변수는 environment.d 에서 작성해야 함으로 java.conf 파일을 다음과 같이 작성해 준다.

이제 elasticsearch.service 를 다음과 같이 작성한다. 이 파일은 ElasticSearch 의 소스가 공개된 GitHub 에서 찾을 수 있다.

Ubuntu 1.604 에서 문제

한가지 문제가 있다. elasticsearch.service 파일을 보면 중간에 리소스를 조정해주는 내용이 나온다.

  • LimitNOFILE=65536
  • LimitNPROC=4096

그런데, 이 설정은 적용되지 않는다. Systemd 에서 시스템 자원 조정을 위한 파일들이 여럿 존재한다.

  1. /etc/systemd/system.conf
  2. /etc/systemd/system/user@1000.service.d/limit.conf – 1000 은 userid 값이다.
  3. .config/systemd/user/elasticsearch.service.d/limits.conf

여기서 3번째는 작동되지 않는다. 1번의 경우에는 전역적으로 모든 사용자에게 적용이 된다.    2번째 경우에는 사용자에게만 적용이 된다.

보통 시스템 리소스는 /etc/security/limits.conf 파일에서 조정하는게 보편적이지만 systemd 는 이처럼 자체적으로 리소스를 제어할 수 있도록 해준다.

systemctl –user 사용법

이제 elasticsearch.service 를 활성화하고 사용법을 익혀보자.

먼저 elasticsearch.service 를 다음과 같이 활성화 해준다.

그리고 서비스 시작/중지는 사용자 계정으로 로그인을 하면 자동으로 시작되며 로그아웃을 하면 중지된다. 하지만 수동으로 시작,중지를 하고 싶다면 다음과 같이 하면 된다.

Systemd for WebLogic 11g

Ubuntu 16.04, CentOS 7, RHEL 7 부터는 Systemd 로 Kernel 의 메인프로세스가 바뀌었습니다. 과거에는 Init 이였는데 이 배포판들은 systemd 로 바뀌었습니다.

리눅스가 부팅하면서 SystemV 인 Run Level 에 따라서 자동으로 시작시키기위한 Init Script 가 존재했었는데, Systemd 도 리눅스가 부팅하면서 시작되도록 하는 Systemd Script 가 존재합니다.

Systemd for WebLogic Administrator

WebLogic 을 Systemd 로 동작하는 배포판에 설치했다면 시작/중지 스크립트를 다음과 같이 작성할 수 있습니다.

WebLogic 의 Admin 서버가 구동될때에 각종 옵션들을 주고 싶다면 “USER_MEM_ARGS” 쉘 환경변수로 지정하고 ‘startWebLogic.sh’ 를 실행하면 그것이 적용된다. Systemd 에서 이러한 환경변수들은 ‘/u01/app/weblogic/config/domains/mCloud/servers/AdminServer/etc/default/adminserver’ 파일에 다음과 같이 정의해 줍니다.

 

Systemd for WebLogic Managed Server

Managed Server 를 시작하기 위해서는 ‘startManagedWebLogic.sh’ 스크립트를 사용하는데, 인자로 서버명을 주어야 합니다. 이것도 Admin 서버와 비슷하게 환경파일을 지정하고 그곳에 정의해주면 됩니다.

‘/u01/app/weblogic/config/domains/mCloud/servers/Server-0/etc/default/server-0’ 는 다음과 같습니다.

물론 USER_MEM_ARGS 환경변수를 지정할 수도 있습니다.

Systemd 등록.

Systemd 에 스크립트를 등록하기 위해서는 ‘/etc/systemd/system’ 디렉토리로 파일을 복사하고 다음과 같은 명령어를 입력해줍니다.

심볼릭 링크가 생성되면서 Systemd 스크립트가 등록이 됩니다. 등록이되면 이제부터 시스템이 꺼질때는 자동으로 WebLogic 도 꺼지고 시스템이 부팅되면 자동으로 시작이 됩니다.