프로그래밍/Docker 검색 결과

3개 발견
  1. 미리보기
    2017.11.12

    Hyper-V에 CoreOS 설치하기(2)

  2. 미리보기
    2017.11.12

    Hyper-V에 CoreOS 설치하기(1)

  3. 미리보기
    2017.07.19

    docker에 대한 형식없는 정리


지난 글에서는 Windows 10에 Hyper-V를 설치한뒤 여기에 가상컴퓨터를 만들어 CoreOS Install ISO 파일이 로딩되어 설치 Prompt 화면까지 보았다. 이번엔 여기까지 진행된 상황에서 CoreOS를 설치하는 과정을 진행하도록 하자.


CoreOS는 ISO 파일을 다운로드 받아 설치를 진행하지만 그 설치 과정에서 인터넷을 접속하여 설치와 관련된 파일을 다운로드 받아 진행하게 된다. 그래서 CoreOS 설치 Prompt 화면에서 네트워크가 이루어지도록 설정해야 할 필요성이 있다. 먼저 이 부분에 대한 내용을 설명하도록 하겠다.


네트워크를 잡기 위해서는 먼저 현재 Network Interface의 이름을 알아둘 필요가 있다. 다음의 명령을 실행해보자




ip addr 이란 명령어를 내리면 현재 설치된 가상컴퓨터의 Network Interface의 이름을 알게 되는데 lo는 Loopback Adapter 이고 eth0가 가상컴퓨터에 설치된 물리적인 Network Adapter 이다. 이 eth0가 우리가 네트워크를 설정해야 할 Network Interface가 된다. 


이제 이렇게 Network Interface의 이름을 알면 vi 에디터를 이용해서 다음의 파일을 작성하도록 한다


sudo vi /etc/systemd/network/static.network


위의 명령어로 vi 에디터가 열리면 다음의 내용을 입력하도록 한다


[Match]
Name=eth0

[Network]
Address=192.168.137.100/24
Gateway=192.168.137.1
DNS=8.8.8.8


Address 항목은 CoreOS에 설정할 IP이다. Address 항목에 설정한 IP 끝에 /24를 넣어줌으로써 Subnet Mask가 255.255.255.0이 된다. 근데 여기 내용을 보면 익숙한 IP가 보인다. 바로 Gateway로 설정된 192.168.137.1 이다. 이게 무슨 IP인가하면 이전 글에서 우리가 내부 가상 스위치를 만들면서 해당 가상 스위치에 설정된 IP가 바로 192.168.137.1이다. 그래서 CoreOS가 사용할 IP를 Gateway로 설정된 192.168.137.1과 같은 IP 영역대인 192.168.137.100을 설정함으로써 네트워크 통신이 이루어지도록 한다. 그리고 이 가상 스위치가 Windows 네트워크 어댑터와 통신을 하면서 인터넷 공유가 설정된 Windows 네트워크 어댑터를 통해 인터넷이 되도록 하는 것이다. 여기서는 CoreOS에 설정할 IP로 192.168.137.100을 사용했을뿐이지 반드시 이렇게 하라는 것이 아니다. 가상 스위치 IP인 192.168.137.1을 제외한 나머지 192.168.137.X IP이면 사용이 가능하다.


이렇게 static.network 파일을 만들면 다음의 명령을 이용해서 Network를 재시작 한다.


sudo systemctl restart systemd-networkd


이렇게 한 뒤에 ping을 이용해서 Window Host IP로 응답이 오는지 확인하고 위에서 DNS로 설정했던 8.8.8.8로도 응답이 오는지 확인한다. 8.8.8.8로 ping 명령을 내려서 응답이 오면 외부 인터넷과의 연결이 된다는 것을 의미한다(응답이 안올경우는 이 글의 마지막에 있는 주의사항을 보고 조치를 취하길 바란다).


ping을 통해 응답을 확인했으면 이제는 설치된 뒤의 계정을 만들 차례다. 다음과 같은 작업을 진행한다.



여기서 내릴 명령어는 sudo openssl passwd -1 > cloud-config.yaml 이다. 이 명령어 라인을 입력받으면 Password: 라고 나오면서 비밀번호를 요구하게 되는데 이때 비밀번호를 입력하고 Verifying - Password: 라고 나왔을때 위에서 입력한 비밀번호를 다시 한번 입력한다. 이런 과정을 거치면 vi나 cat을 이용해서 cloud-config.yaml 파일을 열어보았을때 입력한 비밀번호가 아닌 비밀번호를 암호화한 문자열이 나타난다.


이제 이렇게 만들어진 cloud-config.yaml을 편집할 차례이다. 다음의 명령어를 이용해서 cloud-config.yaml을 편집하자


sudo vi cloud-config.yaml


이 명령어를 실행하면 위에서 설명했다시피 입력한 패스워드가 암호화 된 문자열 한 줄만 있는 문서로 보이는데 이것을 다음과 같이 편집하도록 한다


#cloud-config
hostname: "coreos"
users:
- name: "terry"
  passwd: "$1$JAj어쩌구저쩌구..암호화된 문자열"
  groups:
    - "sudo"
    - "docker"


첫번째 줄은 #cloud-config로 입력한다. hostname은 CoreOS가 설치된 뒤의 hostname을 정하는 것으로 원하는 이름을 지정해주면 된다. name 항목은 계정명을 정하는 것으로 여기서는 terry로 사용했으며 passwd 항목에 위에서 만든 암호회된 문자열이 들어가게끔 한다. 애초에 이 파일을 열면 암호화된 문자열이 보이기 때문에 이 암호화된 문자열이 passwd: 뒤에 오게끔 문서를 편집하면 된다. groups 항목은 계정이 속할 group을 정하는 것으로 sudo와 docker를 지정하도록 한다(이 파일을 편집하기 전에 이 글의 마지막에 있는 주의사항을 읽기를 바란다).


이렇게 문서 편집을 마치면 다음의 명령을 이용해서 본격적으로 설치를 진행하도록 한다


sudo coreos-install -d /dev/sda -C stable -c cloud-config.yaml


이러면 Install 과정을 거쳐서 성공했다고 하는 메시지를 볼 수 있게 된다. 그런 메시지가 나오면 현재 보고 있는 가상컴퓨터 윈도우의 메뉴에서 미디어 -> DVD 드라이브->coreos_...꺼내기 메뉴를 선택하여 가상컴퓨터를 만들때 설정했던 CoreOS ISO 파일을 꺼내는 작업을 한 뒤에 다음의 명령을 내려서 재부팅이 되도록 한다.


sudo reboot


이렇게 재부팅을 하면 CoreOS 로그인 화면이 나오는데 그때 cloud-config.yaml을 만들때 사용했던 계정 이름과 비밀번호를 사용해서 로그인하면 된다.


지금까지 Windows Hyper-V에서 CoreOS를 설치하는 과정에 대해 설명했다. 마지막으로 CoreOS를 설치하면서 부딪쳤던 난관에 대해 정리한 주의사항을 정리하는 것으로 이 글을 마치도록 하겠다.




1. 위에서도 언급했다시피 CoreOS는 설치할때 인터넷이 되도록 설정되어 있어야 한다. 그래서 인터넷 연결이 되는지 확인해야 하는데 이때 사용하는 방법이 DNS 서버로 설정된 IP로 ping을 실행해서 응답이 오는지 확인하는 방법이다(DNS 서버로 통신이 되면 IP가 아닌 도메인으로 접속을 시도하는 것도 가능해지기 때문이다. 실제로 CoreOS는 설치시 자료를 받을때 도메인을 사용해서 자료를 받는다) 근데 ping을 실행해보면 응답이 안되는 경우가 많은데 이럴 경우 체크해야 할 부분이 방화벽이다. 방화벽에서 Hyper-V가 외부와 통신을 하는 것을 막는 경우가 있기 때문에 이런 부분에 대한 체크를 해야한다. 방화벽은 워낙 많은 프로그램이 있어서 여기서는 언급하기는 어려움을 양해해주기 바란다.


2. 무료로 배포되는 바이러스 백신의 경우엔 방화벽을 제공하지 않지만 상용으로 배포되는 바이러스 백신의 경우는 방화벽을 같이 배포하고 있다. 그런데 이렇게 상용으로 배포되는 방화벽의 기능을 끌 경우 컴퓨터에 방화벽이 아주 없어지는 것이 아니다. 상용으로 배포되는 방화벽 기능을 끄게 되면 자동으로 Windows 에서 제공하는 방화벽이 올라가기 때문에 상용으로 배포되는 방화벽 기능을 껐다고 해서 방화벽이 없다고 판단하면 안된다. 테스트를 하기 위해 상용으로 배포되는 방화벽을 껐다면 제어판에 들어가 Windows에서 제공하는 방화벽 기능이 현재 올라와 있는지 살펴보고 이것도 꺼야 방화벽 기능이 꺼졌다고 말할 수 있다.


3. 설치과정에서 네트워크 환경을 잡은것은 어디까지나 설치하기 위한 네트워크를 잡은 것이지 설치가 끝난 뒤의 네트워크 환경이 이루어지는 것은 아니다. 위에서 우리가 IP와 Gateway와 DNS를 잡았지만 그것은 어디까지나 설치하는 동안에 사용되는 것이지 설치가 된 뒤에 CoreOS가 우리가 설정한 내용으로 IP와 Gateway와 DNS가 설정되는 것은 아니라는 뜻이다. 설치가 된 뒤의 CoreOS의 네트워크 세팅은 아무것도 되어 있지가 않다. 그렇기땜에 설치가 된 뒤에 다시 위에서 진행했던 네트워크 셋팅 과정을 다시 한번 거쳐서 설치된 뒤의 CoreOS 네트워크 설정을 하도록 하자.


4. 설치가 다 마쳐서 인터넷이 되는것까지도 확인했는데도, 컴퓨터를 재부팅하면 CoreOS가 인터넷이 안되는 상황이 벌어진다. 네트워크 설정을 건드린것도 없었는데 안되어서 답답했었다. 가상 스위치도 ping이 되고 Windows Host ip로도 ping이 되는데 인터넷이 되질 않았다. 근데 이유를 보니 컴퓨터를 재부팅하면 이전 글에서 설명했던 Windows 네트워크 어댑터 공유 설정에서 원인이 있었다. 공유 설정이 되어 있는데도 재부팅을 하면 공유가 되지 않아서 인터넷이 안되는 그런 상황이 벌어졌다. 그래서 이럴 경우엔 공유 설정을 풀어서 확인 버튼을 클릭하며 공유 해제작업을 마친뒤 다시 공유 설정을 해서 확인 버튼을 클릭하면 정상적으로 동작한다. 이것은 비단 재부팅하는 상황뿐만이 아니라 위에서 설명했던 1,2번에서도 이 과정을 해봐야 한다. 이걸 해서 풀리는 경우도 있었다. 또한 컴퓨터에 전원을 넣고 켠 시점에서도 이 상황이 발생하기 때문에 전원을 켜서 부팅이 완료되면 공유 설정작업을 다시 진행해줘야 한다. 개인적으로 이 상황땜에 가상 컴퓨터를 몇번을 지우고 깔았는지 모를 정도로 가장 풀기 힘들었던 상황이었다.


5. cloud-config.yaml 파일을 만들때 users 항목의 name 항목을 통해 계정 이름을 정하게 되는데 이때 계정 이름으로 docker를 사용하면 안된다. 원래 CoreOS를 설치했던 가장 큰 이유는 docker 때문인지라 알기 쉽게 할려고 계정 이름과 패스워드를 docker로 했는데 설치는 이루어졌지만 설치된 뒤에 로그인 시 cloud-config.yaml 파일에 설정한 docker 계정과 해당 패스워드로 로그인을 할 수 없다. 이유는 CoreOS는 배포본 안에 docker 란 계정이 이미 존재하고 있어서 이와 같은 문제가 발생한 것이었다. 그래서 계정 이름으로 docker를 사용하면 안된다.


6. Hyper-V를 통해서 CoreOS 가상 컴퓨터를 시작한뒤 접속하면 화면에서 의미를 알 수 없는 문구들이 중간중간 나타나서 작업할때 불편한 것이 있다. 그래서 Hyper-V로는 CoreOS 가상 컴퓨터를 시작만 하고 접속은 putty를 이용해서 해당 가상 컴퓨터에 접속하면 편하다. 이때 프로토콜은 ssh를 사용하고 ip는 네트워크 설정과정에서 지정한 가상컴퓨터 ip를 사용하면 된다. 물론 포트번호는 ssh를 사용하기 때문에 22번을 사용한다

 


참고사이트 : Docker를 위한 CoreOS - Install




'프로그래밍 > Docker' 카테고리의 다른 글

Hyper-V에 CoreOS 설치하기(2)  (0) 2017.11.12
Hyper-V에 CoreOS 설치하기(1)  (0) 2017.11.12
docker에 대한 형식없는 정리  (0) 2017.07.19

트랙백을 확인할 수 있습니다

URL을 배껴둬서 트랙백을 보낼 수 있습니다

다른 카테고리의 글 목록

프로그래밍/Docker 카테고리의 포스트 목록을 보여줍니다

이번 글에서는 Windows에서 Docker를 사용하기 위한 첫번째 작업으로 Hyper-V에 CoreOS를 설치하는 작업을 설명해보고자 한다. Docker를 배포하는 Docker Inc. 에서는 원래 Windows 용으로 Docker for Windows를 배포한다. Docker for Windows 또한 Hyper-V에 MobyLinux를 설치해서 Docker를 운영한다. 근데 왜 CoreOS로 바꾸는가 하면 Docker용 Linux 컨테이너에서 systemctl 같은 서비스 관리 명령어를 사용하기 위해서였다(처음엔 이것을 하기 위해 Docker for Windows에서 해봤으나 기능이 되질 않아 CoreOS로 바꾸어서 결국 기능을 구현하긴 했지만 구현에 성공한 방법을 정작 Docker for Windows에서 해보지 않았기 때문에 Docker for Windows에서도 구현될 수도 있을 가능성이 있음을 미리 밝혀둔다).


먼저 Hyper-V를 설치하도록 한다. Docker for Windows의 경우 Windows 10의 빌드번호가 10586 이상이어야 가능하다. 그래서 본인의 Windows 10 빌드번호를 먼저 확인하기 바란다(Windows 10 Anniversary Update가 적용된 버전이면 이 빌드번호가 된다. 검색해보면 기존의 Windows 10 에서 Anniversary Update로 업그레이드할 경우 동작이 되지 않는다는 내용도 있어서 진행해보고 안될 경우 아예 클린방식으로 새로이 업그레이드된 버전으로 설치해보길 바란다) Windows 10의 제어판->프로그램 및 기능에 들어가서 해당 화면의 왼쪽에 있는 Windows 기능 켜기/끄기를 선택하면 아래와 같은 창이 나오는데 여기에서 Hyper-V 항목을 찾아 다음과 같이 체크한뒤 확인 버튼을 클릭하면 Hyper-V 설치를 마치게 된다.






Hyper-V를 설치하면 Windows 10에 다음과 같이 Windows 관리도구로 Hyper-V가 새로이 추가된다




이제 메뉴에서 Hyper-V 관리자를 클릭하면 다음의 화면이 나타난다.




이 화면에서 이제 CoreOS가 설치될 가상 컴퓨터를 설치해야 한다. 근데 그 전에 해야 할 것이 있다. 바로 가상 스위치를 만들어야 한다. 이것의 역할은 Windows 10과 가상 컴퓨터와의 네트워크를 중간에서 이어주는 역할을 하게 된다. 그래서 이제 이 가상 스위치를 만들어보도록 하자. Hyper-V 관리자 화면의 오른쪽을 보면 가상 스위치 관리자 란 항목이 있는데 이것을 클릭하면 다음의 화면이 나타난다.




이 화면에서 가상 스위치 유형을 내부로 선택한뒤 가상 스위치 만들기 버튼을 클릭하면 다음의 화면이 나타난다




이름 항목은 적당한 이름을 주고(여기서는 NAT로 주었다. 실제 NAT 역할을 하기땜에..) 이전 화면에서 가상 스위치 유형을 내부로 설정했기 때문에 연결형식은 자동으로 내부 네트워크로 설정되어 있다. 이런 상태에서 확인 버튼을 클릭해준다. 그러면 NAT라는 이름의 가상 스위치가 생성이 된다. 이렇게 생성된 가상 스위치는 제어판 -> 네트워크 및 공유 센터 화면에서 화면 왼쪽에 있는 어댑터 설정 변경을 클릭하면 다음과 같이 나타나게 된다.




이제 Windows 10에서 사용중인 네트워크 연결(각자 사용하는 PC에서는 이름이 다르겠지만 여기서는 위의 화면을 기준으로 이더넷으로 하겠다)을 공유해야 한다. 이더넷에서 마우스 우클릭해서 속성을 들어간뒤 공유 탭을 클릭하면 다음의 화면이 나타난다. 여기에서 첫번째 항목인 다른 네트워크 사용자가 이 컴퓨터의 인터넷 연결을 통해 연결할 수 있도록 허용(N) 항목을 체크하고 아래에 있는 다른 네트워크 사용자가 공유 인터넷 연결을 제어하거나 중지시킬 수 있도록 허용(O) 항목은 체크해제 하도록 한다(지금은 네트워크 연결이 2개뿐이 없어서 이렇게 나오지만 노트북에서 진행할 경우 무선 어댑터가 있기 때문에 네트워크 연결이 3개가 된다. 네트워크 연결이 3개 이상이 되면 첫번째 항목에서 공유할 네트워크 연결을 선택할 콤보박스가 나오는데 이때 vEthernet(NAT)를 선택해주면 된다) 확인 버튼을 클릭하면 다음과 같은 대화상자가 나오는데 여기에서 예를 눌러준다. 그러면 vEthernet(NAT)는 IP가 192.168.137.1을 갖게 된다. 






이쯤에서 이렇게 하는 이유에 대해 간단히 언급하겠다. 위에서 가상 스위치 유형을 만들때 가상 스위치 유형을 내부로 지정해서 만들었다. 이 유형에는 외부, 내부, 개인 이렇게 3가지가 있는데 외부는 Host 컴퓨터(여기서는 Windows 10)의 네트워크 영역대를 그대로 이용하게 된다. 예를 들어 Windows 10의 IP가 192.168.0.17이면 외부는 192.168.0.100 같이 같은 네트워크 영역대를 사용하면서 Host 컴퓨터 뿐만 아니라 Host 컴퓨터와 같은 영역대의 컴퓨터와 위에서 언급한 별도의 공유 절차 없이 통신을 할 수 있게 된다. 내부는 외부와는 달리 다른 네트워크 영역대(위에서 설정하게 된 192.168.137.1 같은 전혀 다른 네트워크 영역대)를 갖게 된다. Host 컴퓨터와는 통신이 되지만 Host 컴퓨터와 같은 네트워크 영역대의 컴퓨터와는 통신이 이루어지지 않는다. 정리하면 192.168.137.X대의 독자적인 네트워크 영역을 구축한다고 보면 된다. 외부로 할 경우엔 가상 컴퓨터가 Host 컴퓨터와 같은 영역대의 IP를 사용하기 때문에 네트워크의 부담이 줄어드는 장점이 있지만 노트북 같이 이동하는 상황이 잦아서 그에 따른 네트워크 IP가 유동적으로 바뀌어야 하는 경우 이에 대한 IP를 일일이 수정해야 하는 불편함이 있다. 내부의 경우는 이 가상 스위치를 통해 이 스위치로 설정된 모든 가상 컴퓨터와 네트워크 자원을 공유해서 네트워크의 퍼포먼스는 떨어지지만 이동하는 상황이 잦은 경우 내부는 독자적인 네트워크 이므로 IP를 수정할 필요가 없다. 그래서 외부 스위치는 운영서버 같이 네트워크 IP가 고정적이고 네트워크 자원을 독점해서 사용해야 하는 환경에서 좋고 내부 스위치는 개발 노트북 같이 네트워크 IP가 유동적이고 네트워크 자원을 공유해야 사용해야 하는 환경에서 좋다.


가상 스위치 만드는 작업을 마쳤으면 이제 가상 컴퓨터를 만들어보도록 하자. Hyper-V 관리자 화면에서 오른쪽 메뉴를 보면 새로 만들기 란 항목이 있는데 이것을 클릭하면 조그만 팝업 메뉴가 나타난다. 여기서 가상 컴퓨터를 선택하면 다음과 같은 화면이 나타난다. 이 화면에서 다음을 눌러 진행한다.




이름 및 위치 지정 화면에서 적당한 이름을 준다. 만약 가상 컴퓨터를 다른 위치에 저장하려 할 경우엔 다음 화면과 같이 가상 컴퓨터를 다른 위치에 저장 항목을 체크한뒤 활성화 되는 찾아보기 버튼을 클릭해서 해당 폴더를 지정해주면 된다. 이 화면에서 다음을 눌러 진행한다.



세대 지정 화면에서는 1세대를 선택한뒤 다음을 눌러 진행한다.




메모리 할당은 자신의 컴퓨터 메모리를 고려해서 적당하게 지정해준다. 여기서는 4기가(4096 MB)를 설정했는데 컴퓨터의 물리 메모리가 32기가라 4기가로 설정한 것이지 모든 환경에서 이렇게 하라는 것이 아니다. 이 화면에서 다음을 눌러 진행한다




네트워크 구성 화면에서는 연결을 선택해줘야 하는데 이때 위에서 만들었던 내부 가상스위치(여기서는 NAT로 만들었기 때문에 NAT를 선택한다)를 선택해주도록 한다. 이 화면에서 다음을 눌러 진행한다.




가상 하드 디스크 연결 화면에서는 현재 만들고자 하는 가상 컴퓨터의 가상 하드 디스크를 만들게 되는데 이름과 위치는 건드릴 필요는 없고 크기를 지정해야 한다. 이때 10 GB 이상은 되어야 한다. 이렇게 한 이유가 있는데 밑에서 바로 언급하겠지만 CoreOS의 설치 용량을 몰라서 CoreOS의 인스톨 ISO를 보고 판단하게 되었다. CoreOS의 Install ISO 파일이 300 MB도 안되어서 4GB로 주어서 진행했었는데 가상 컴퓨터를 만드는데는 문제가 없었으나 CoreOS Install에는 실패했었다. 그래서 다시 가상 컴퓨터를 만들어서 이 용량을 10 GB로 주니 문제없이 해결이 되었다. 나는 여유가 있어서 40 GB로 주었다. 40 GB로 주어도 처음에 이 용량을 40 GB로 만들고 시작하진 않는다. Docker Hub를 통해 배포되는 이미지가 일반적으로 500 MB가 넘는것이 드물지만 이런 이미지를 여러개 갖고 있게 되며 이 이미지가 컨테이너로 올라갈 경우 필요에 따라 파일을 CoreOS에서 관리해야 할 필요성도 있어서 40 GB로 좀 여유있게 주었다. 이 화면에서 다음을 눌러 진행한다.



설치옵션 화면에서는 부팅 가능 CD/DVD-ROM에서 운영 체제 설치(C) 항목을 선택한 뒤 이미지 파일(.iso)(I) 항목을 선택하고 CoreOS Install ISO 파일을 지정해주면 된다. CoreOS Install ISO 파일은 https://coreos.com/os/docs/latest/booting-with-iso.html 에서 Stable Channel 탭에서 Download Stable ISO 버튼을 클릭하면 다운로드 받을 수 있다. 이 화면에서 다음을 눌러 진행한다.




요약 화면에서는 지금까지 설정한 항목들에 대한 내용들을 최종적으로 보여주게 된다. 여기서 마침 버튼을 누르면 가상 컴퓨터를 만들게 되며 Hyper-V 관리자 화면에서 방금 만들어진 가상 컴퓨터가 보이게 된다.




이렇게 보이는 가상 컴퓨터(여기서는 CoreOS) 항목을 마우스 우클릭을 하면 팝업 메뉴가 나타나는데 여기서 연결을 선택한다. 연결을 선택하면 다음 화면과 같이 별도의 새 창이 나타난다. 이것은 비유하면 아직 전원이 들어오지 않은 컴퓨터라 여기면 된다. 


이 화면에서 녹색으로 된 동그란 모양의 시작 버튼을 누르거나 화면에서 안내해주듯이 시작을 선택하면 가상 컴퓨터를 만들면서 설정했던 CoreOS Install ISO 파일로 부팅을 하면서 가상 컴퓨터기 기동을 하게 되어 다음과 같이 보이게 된다.




오해를 할까봐 하는 말인데 이 화면은 CoreOS 가 설치가 마쳐진 뒤에 나오는 화면이 아니다. Windows 설치 과정으로 비유하면 우리가 Windows Install USB 디스크를 컴퓨터에 꽃은뒤 전원을 켜서 USB로 부팅하면 Windows 설치 화면을 보여주는데 이런 Windows 설치 화면과 같은 개념의 화면이 이 화면이라고 보면 된다. CoreOS는 명령어를 이용해서 설치하는 작업을 거치기 때문에 이런 Text 기반의 Prompt 화면으로 보여지게 되는 것이다. 이 화면에서 중간중간에 이상한 문구들이 나타나지만 이런것들은 무시하면 된다.


이번 글에서는 Hyper-V 설치 및 CoreOS를 설치하기 위한 가상 컴퓨터 생성에 대해 알아보았다. 다음 글에서는 이렇게 나온 CoreOS 설치 화면에서 진행해야 하는 CoreOS 설치에 대해 알아보도록 하겠다.



'프로그래밍 > Docker' 카테고리의 다른 글

Hyper-V에 CoreOS 설치하기(2)  (0) 2017.11.12
Hyper-V에 CoreOS 설치하기(1)  (0) 2017.11.12
docker에 대한 형식없는 정리  (0) 2017.07.19

트랙백을 확인할 수 있습니다

URL을 배껴둬서 트랙백을 보낼 수 있습니다

다른 카테고리의 글 목록

프로그래밍/Docker 카테고리의 포스트 목록을 보여줍니다

docker 공부하면서 case by case로 체계없이 정리한 것들을 기록한 것들이다.

이 내용들은 늘어나거나 줄어들거나 수정될 수 있다는 것을 미리 말해둔다

말그대로 docker를 공부하면서 알게된 단편 지식들을 보관 차원에서 적어둔 것이기 때문이다


1. docker hub에서 이미지를 받을때는 pull 명령을 사용한다. 예를 들어 wildfly의 최신버전(latest)를 받을 경우 다음과 같이 한다.


docker pull jboss/wildfly:latest


2. 내가 받은 이미지들의 목록을 볼 경우 다음과 같이 한다


docker images


3. 이미지 세부 정보를 확인할 때는 inspect 명령어를 사용한다.


docker inspect jboss/wildfly:latest


세부 정보는 json 문자열 형태로 보여지며 주요 정보로는 이미지 ID, 생성일, Docker 버전, 이미지 생성자, CPU 등을 제공한다

정보가 json 문자열 형태로 길게 나오기때문에 만약 특정 정보를 보고자 할때는 다음과 같이 format 옵션을 주어 보고자 하는 항목을 지정하면 그 항목에 대해서만 볼 수 있다. 예를 들어


docker inspect --format="{{ .Os}}" jboss/wildfly:latest


를 사용하면 Os 항목에 대한 값만 알 수 있다. 또 Config 항목의 하위 항목으로 있는 Hostname 항목 값을 알고자 할때는 다음과 같이 한다


docker inspect --format="{{ .Config.Hostname}}" jboss/wildfly:latest


이것은 우리가 json 문자열을 객체로 만들었을때 접근하는 방법을 생각하며 이 명령을 사용하면 된다


4. 이미지를 삭제할때는 다음과 같이 한다


docker rmi jboss/wildfly:latest


5. docker 이미지를 받았으면 이제 이 이미지를 가지고 하나의 컨테이너를 생성해서 실행시키도록 한다. 이해하기 쉽게끔 설명하자면 프로그래밍에서 얘기하는 클래스와 객체로 설명하면 이해하기 쉬울듯 하다.


A라는 클래스를 이용해서 객체를 만들때..


A b = new A();

A c = new A();


이렇게 만들것이다. A라는 클래스를 이용해서 만든 객체 b와 c가 있지만 이 b와 c는 서로를 간섭하지는 않는다. 이것을 docker에 비춰보면 클래스는 이미지가 되고 객체는 컨테이너가 된다. 필요성에 따라 이미지를 이용해서 0개 이상의 컨테이너를 만들수 있지만 이렇게 만들어진 컨테이너들은 서로 독립적인 공간이 되어 서로 간섭하지를 않게 된다


컨테이너의 라이프 사이클은 docker 명령어를 빌려서 설명을 하자면 create(생성) -> start(시작) -> stop(중지) -> rm(삭제) 개념으로 흘러가며 create와 start를 같이 해주는 명령어인 run이 있고 start인 상태에서 중지했다가 다시 시작하는 명령어로 restart가 있다


6. docker에서 컨테이너를 생성하면서 동시에 시작할때는 run을 사용한다. wildfly를 예로 들자면 다음과 같이 한다


docker run -it --name "wildfly" -p 8080:8080 jboss/wildfly:latest


run 명령어를 사용하면서 같이 사용된 옵션에 대해 설명을 하자면 


-i 옵션은 컨테이너 표준 입력을 연다는 뜻이고, -t는 tty(단말 디바이스)를 사용한다는 의미이다. 이 둘을 묶어서 -it로 사용한 것이다. 


--name 옵션을 주면 해당 컨테이너에 대해 특별한 이름을 부여하는 옵션이다. 컨테이너를 start 명령어로 시작하거나 stop 명령어를 이용해서 종료할때 대상 컨테이너를 지정하기 위해 컨테이너 ID를 입력해야 하는데 이 ID라는게 의미가 없는 숫자/문자가 조합된 문자열이라 타이핑하기 어렵다. 이러한 상황을 좀더 쉽게 사용하게 하기 위해 --name 옵션을 주어 의미있는 문자열을 지정함으로써 차후에 start, stop 명령어를 사용할때 그 문자열을 사용하여 해당 명령어를 쉽게 실행할 수 있다.


-p는 호스트와 컨테이너 간의 포트를 연결하는 옵션이다. wildfly는 8080 포트를 이용해서 통신하게 되는데 이것은 어디까지나 컨테이너의 8080 포트를 열은 것이기 때문에 우리가 테스트하기위해 브라우저에서 http://localhost:8080을 입력해도 동작이 이루어지지 않는다. 이로 인해 호스트의 8080 포트를 컨테이너의 8080 포트와 연결해야 제대로 된 동작을 할 수 있다.  한가지 더 첨언을 하자면 컨테이너가 8080 포트를 열었다고 해서 호스트도 반드시 8080 포트를 열으라는 법은 없다. 예를 들어 wildfly 컨테이너를 2개 이상 운영하는데 두 컨테이너가 모두 8080 포트를 열어도 문제가 되는 것은 없다. 그러나 이 두 포트를 모두 호스트의 8080 포트에 연결할 수는 없다. 즉 둘 중 하나의 컨테이너는 -p 8081:8080 이런 식으로 호스트의 8081 포트를 컨테이너의 8080 포트로 열어서 동작하게끔 해야한다


7. 6번의 과정으로 실행을 하게 되면 docker의 foreground로 실행하는 것이기 때문에 이런 식으로의 실행은 추천하지 않는다.  즉 다른 컨테이너를 시작할려면 다시 쉘 창을 열어서 docker 관련 명령을 실행해야 하기 때문이다. 대신 foreground에서 실행시키는 것이기 때문에 컨테이너를 중지할려면 ctrl-c를 눌러 중지할 수 있으며 관련 콘솔 로그 내용도 바로 확인 할 수 있는 장점은 있다. 그러나 docker로 실행되는 것이 WAS나 DB 서버 같은 서버용 프로그램인것을 감안하면 background로 실행되는 것이 좋다


8. 7번에서 설명한대로 background로 컨테이너가 실행되게끔 할려면 -d 옵션을 붙이면 된다


docker run -d --name "wildfly" -p 8080:8080 jboss/wildfly:latest 


6번에서 설명했을때는 -it옵션을 붙였으나 여기서는 background로 실행하는 것이기 때문에 컨테이너 표준입력을 사용할 수가 없다. 그걸 제외한 나머지 옵션은 동일하다

그러나 이렇게 실행하면 6번에서 컨테이너가 보여주는 로그들을 볼 수 없는 문제가 있다. 이를 볼려면 logs 명령어를 사용하면 된다


docker logs -f wildfly


-f 옵션은 linux 에서 tail 명령 사용했을때 -f 사용한 것을 생각하면 된다. 즉 로그를 계속 연속성으로 보여주는 것으로 이해하면 된다. 뒤에 wildfly가 붙은 것은 우리가 docker run을 이용해서 컨테이너를 실행할때 --name 옵션을 이용해서 주었던 그 wildfly이다. 이렇게 컨테이너를 run 명령어를 이용해서 실행할때 --name 옵션으로 별칭 준것을 docker 관련 명령 실행시 특정 컨테이너를 지칭하는데 사용함으로써 편리함을 준다.


9. 처음에 docker를 접하면서 난 docker의 이미지가 프로그램들의 모음(예를 들어 wildfly 컨테이너를 예로 들자면 wildfly와 이를 실행시키기 위해 필요한 부가적인 프로그램(예를 들면 jdk 같은)들의 모음)으로 이해했다. 그러나 docker 관련 구성도를 보면서 이해하게 된것은 컨테이너 안에는 os가 있다는 것이다. 즉 os 안에 관련 프로그램이 설치되어 있는 개념인 것이다. 이 부분은 나중에 build를 공부하면서 확연히 알게 되었다. 즉 기본 베이스 이미지를 centos 같은 리눅스 이미지로 삼은뒤 여기에 apache를 yum 명령어로 설치하면서 이미지 만드는 법을 알게 되었다 물론 베이스 이미지를 centos 같은 os 이미지가 아니라 wildfly 이미지를 사용할 수 있다. 그렇다해도 wildfly에 centos가 이미 있기 때문에 결국 wildfly 이미지에 있는 centos 를 이용하는 것임에는 변함이 없다. 이러한 개념이기 때문에 해당 컨테이너는 독자적인 OS와 그에 따른 환경변수를 가지고 실행할 수가 있는것이며 서로간의 컨테이너에 영향을 주지 않고 독립적으로 움직이게 되는 것이다.


docker 이미지는 os가 포함이 되어 있는 0개 이상의 프로그램이 설치되어 있는 이미지이다


10. 9번에서 설명했다시피 이미지는 자체적으로 OS가 포함되어 있다고 했다. 그렇기 때문에 우리는 컨테이너가 실행중일때 이 컨테이너를 구동시키는 기반이 되는 OS에 접속할 수가 있다. 즉 우리가 wildfly 이미지를 이용하여 컨테이너를 실행중일때 이 컨테이너의 OS에 연결할 수 있다는 것이다. 이것은 나름 작업(?)적인 차원에서 중요한 의미가 있다. 예를 들어 우리가 wildfly에서 구동중인 web application을 만든다고 가정해보자. 그러면 파일 업로드 기능을 넣어야 하는데 파일 업로드를 하게 되면 OS에서 관리되는 디렉토리 중 하나에 사용자가 업로드한 파일이 있어야 하며 그러한 디렉토리를 만들어놔야 한다. 그러면 이 디렉토리를 만들려면 wildfly 컨테이너의 os 쉘에 접근해서 디렉토리를 만드는 명령(mkdir)을 실행해야 한다. 이러한 OS 쪽의 작업을 하거나 또는 wildfly의 설정파일(예를 들면 standalone.xml)을 수정할 수 있다. 그리고 이렇게 변경이 된 내용이 있는 컨테이너를 docker commit 명령을 이용해서 새로운 이미지로 만들어 이를 다른 사람에게 배포할 수 있다.


서론이 길었는데 이 기능을 수행하는것에 대해 설명하도록 하겠다

먼저 경우를 분리해서 생각해야 할 부분이 있는데 우리가 컨테이너를 실행시킬때 /bin/bash 같은 쉘을 실행시킨 상황과 그렇지 않은 상황으로 분리해야한다. /bin/bash를 실행시켜서 현재 컨테이너가 bash shell이 실행중인 상황이면 docker의 attach 명령을 이용해서 접속하면 된다


docker attach wildfly


이러면 bash shell 에 접속하여 shell 명령어를 실행시킬수 있다. 여기서는 컨테이너 이름을 지칭하기 위해 wildfly를 썼지만 실제로 wildfly는 이렇게 명령해도 접속이 되질 않는다. 왜냐면 wildfly는 bash shell을 실행시키지 않고 컨테이너를 띄우기 때문이다. 때문에 attach 명령으로 접속 시도를 해도 동작이 되질 않는다. 또한 백그라운드로 실행시킨 컨테이너의 경우도 마찬가지이다(왜 그런지는 곰곰히 생각해보면 이해하기 쉽다. 우리가 background로 컨테이너를 실행시킨다는건 docker 명령어를 실제로 내리는 shell 창에서 억세스하는 것이 아니라 말그대로 background로 돌리는 것인데 거기서 shell 명령을 실행시키는 /bin/bash가 실행될리가 없잖은가?) 이렇게 /bin/bash 를 실행시키지 않고 시작한 컨테이너나 또는 background에서 실행중인 컨테이너를 접속하기 위해서는 exec 명령을 사용해서 /bin/bash를 실행시켜 접속하면 된다


docker exec -it -u root wildfly /bin/bash


이렇게 exec 명령을 통해 /bin/bash를 실행시켜서 bash shell 명령을 실행시킬수가 있게 된다. -u는 os의 어떤 계정을 통해서 명령을 실행시킬것인지를 지정하는 것이다. 그러면 어떤 계정을 사용해야 하는가? 그것은 해당 컨테이너의 docker 이미지를 build 하는데 사용된 Dockerfile의 소스를 보면 알 수 있다. 


일반적으로 docker 이미지들은 github 에서 이미지 관련 파일들이 존재하여 이를 github에서 빌드하여 docker hub에 배포되는 형태를 취하고 있다. 그래서 이 Dockerfile의 소스를 볼려면 github을 봐야한다. wildfly를 예로 들면 docker hub의 wildfly에 대한 페이지(https://hub.docker.com/r/jboss/wildfly/)를 가보면 Source 항목에 github과 링크되어 있는 링크를 볼 수 있다. 이를 클릭하면 github에 있는 해당 이미지를 빌드하는데 사용된 Dockerfile을 볼 수 있게 된다. 이 Dockerfile 을 클릭해서 상세 내용을 보면 USER 란 항목이 있어 Dockerfile을 이용해 빌드하면서 실행하게 되는 명령어를 수행하는 OS 계정을 언급하게 된다. 바로 이 USER 항목에 언급된 계정을 -u 옵션 뒤에 사용해주면 된다.  모든 docker 이미지가 root 계정을 사용하는 것은 아니기 때문에 이것을 확인하고 진행하기 바란다.


attach와 exec에 대한 추가 설명

위의 내용을 읽어보면 bash shell 기능을 위주로 설명했기때문에 현재 bash shell이 실행중인 컨테이너를 접속하여 할때는 attach, bash shell 이 실행중이지 않은 컨테이너를 접속하려 할때는 exec를 사용하는 것으로 이해가 될 것 같아서 부가설명을 하고자 한다.


attach는 현재 실행중인 컨테이너에 접속 한다고 보는 것이 맞다. docker 이미지가 컨테이너로 생성되면서 run이 될때 이미지 가 내부적으로 특정 프로그램을 실행시킬수도 있고 또는 run 명령을 내리는 시점에서 특정 프로그램을 실행 시키게도 할 수 있다. 이때 bash shell 이 실행되도록 /bin/bash 를 실행시켜서 attach 시 바로 bash shell prompt가 보이게끔 할 수도 있다. 그러나 그렇지 않은 이미지도 있다. 예를 들어 위에서 언급했던 wildfly 이미지의 경우 이 이미지는 컨테이너로 올라가는 시점에 wildfly의 standalone.sh 스크립트가 실행시켜 wildfly가 구동되도록 하고 있기 때문에 콘솔 화면에서 wildfly의 로그가 올라오는 것을 볼 수 있다. 그래서 docker의 attach 명령을 이용해서 wildfly의 컨테이너를 접속하면 wildfly 구동되고 있는 상황에서 나오는 콘솔로그를 볼 수 있다. 또한 이 상태에서 ctrl-c를 클릭하면 wildfly 가 실행되는 것이 종료되는 것을 볼 수 있다.


이에 반해 exec는 현재 실행중인 컨테이너에 특정 shell script를 실행하는 것이라고 보는게 맞다. 예를 들어 wildfly 이미지의 컨테이너가 wildfly란 이름으로 컨테이너가 실행되어 있는 상태에서 docker exec -it wildfly /bin/bash 로 명령을 내리면 해당 컨테이너에 bash shell을 실행시키는 것이다. 그래서 bash shell prompt가 화면에 나오게 되는 것이다. 만약 /bin/bash가 아는 사용자가 만든 별도 스크립트를 실행시키면 그 스크립트가 실행시키는 것이다(exec 명령어를 사용할때 -it 옵션을 주었기 때문에 해당 명령의 실행 결과가 현재 보는 화면에 바로 보이게 된다)


11. docker 에서 등록되어 있는 컨테이너 목록을 확인 하는 명령은 다음과 같이 한다


docker ps -a 


-a 옵션을 빼고 docker ps 로 실행하게 되면 현재 동작중인 컨테이너만 보여주기 때문에 중지되어 있는 컨테이너는 보여주지 않게 된다. 그래서 -a 옵션을 항상 붙여서 중지되어 있는 것도 같이 확인하는 버릇(?)을 들이는 것이 좋다


12.  docker에서 실행중인 각 컨테이너가 사용하는 CPU 및 메모리 점유율 등 컨테이너의 상태를 확인하기 위해서는 다음의 명령을 사용한다


docker stats


13. 중지되어 있는 컨테이너를 구동하는 명령은 다음과 같이 한다


docker start wildfly


14. 실행중인 컨테이너를 중지시키는 명령은 다음과 같이 한다.


docker stop wildfly


15. 컨테이너를 재시작할때의 명령은 다음과 같이 한다


docker restart wildfly


16. 컨테이너를 삭제할때의 명령은 다음과 같이 한다


docker rm -f wildfly


원래 컨테이너를 삭제할때는 현재 상태가 중지되어 있는 컨테이너만 삭제가 가능하기 때문에 실행중인 컨테이너는 삭제를 할 수가 없다. 그러나 -f 옵션을 붙이면 실행중인 컨테이너도 삭제하게 된다

현재 컨테이너에 등록되어 있는 모든 컨테이너를 삭제하고자 할 때는 다음과 같이 한다


docker rm $(docker ps -a -q)


여기에 위에서 설명한 -f 옵션을 붙이면 실행중인 컨테이너까지 모두 삭제하게 된다


17. 현재 구동중인 컨테이너에서 실행 중인 프로세스를 모두 일시정지 시키고자 할 때는 다음과 같이 한다


docker pause wildfly


일시정지된 컨테이너를 docker ps 명령어를 이용해서 컨테이너 목록으로 확인해보면 Status에 Paused로 나온다(참고로 stop 명령을 이용해서 컨테이너를 중지시킨 경우 docker ps 명령을 이용해 목록을 확인해보면 Status에 Exited로 나온다)

이렇게 일시정지된 컨테이너를 다시 재시작 시킬때는 다음과 같이 한다


docker unpause wildfly


18. 현재 구동중인 컨테이너에서 실행중인 프로세스를 확인할때는 다음과 같이 한다


docker top wildfly


linux에서 top 명령을 실행한것과 같은 유형의 결과물을 보여준다


19. 구동중인 컨테이너에서 실행중인 프로세스가 이용중인 포트를 확인하고자 할때는 다음과 같이 한다


docker port wildfly


이렇게 하면 우리가 위에서 실행한 wildfly의 경우 다음과 같이 나타날 것이다


8080/tcp ->0.0.0.0:8080


이것은 컨테이너의 8080 포트(왼쪽의 8080/tcp)를 호스트 컴퓨터(정확하게는 현재 내가 사용중인 OS)의 8080 포트(오른쪽의 0:.0.0.0:8080)와 연결되고 있음을 의미한다.


20. 컨테이너와 호스트 컴퓨터 간의 파일 복사는 다음과 같이 한다


docker cp wildfly:/opt/jboss/wildfly/standalone/configuration/standalone.xml D:/dockerimages


위의 명령은 wildfly 컨테이너의 /opt/jboss/wildfly/standalone/configuration 디렉토리에 있는 standalone.xml 파일을 호스트 컴퓨터의 D:/dockerimages  디렉토리에 복사한다는 뜻이다. 

명령어의 구조가 docker cp 복사대상파일 복사되는위치 구조이기 때문에 이 구조만 맞춰주면 마찬가지로 호스트에서 컨테이너로 파일 복사를 할 수 있다. 위에서 언급한 명령을 호스트에서 컨테이너로 복사하는 개념으로 바꿔서 한다면 다음과 같이 한다


docker cp D:/dockerimages/standalone.xml wildfly:/opt/jboss/wildfly/standalone/configuration


이렇게 하면 호스트 컴퓨터의 D:/dockerimages/standalone.xml 파일을 wildfly 컨테이너의 /opt/jboss/wildfly/standalone/configuration 디렉토리에 복사하게 된다. 명령어를 유심히 보면 알겠지만 컨테이너의 디렉토리나 디렉토리에 있는 파일을 언급할때는 컨테이너 이름과 컨테이너의 디렉토리 또는 파일 사이에 :(콜론)을 붙인다(wildfly:/opt/jboss/wildfly/standalone/configuration/standalone.xml)


21. 기본적으로 Docker에서 실행되는 명령은 OS의 root 계정으로 실행이 된다(그도 그럴것이 Dockerfile에서 ENV를 이용해서 OS의 환경변수도 설정이 가능하기 때문에 이런것이 가능할려면 root 계정일수 밖에 없다) 그러나 root 계정이 아닌 다른 계정을 만들어서 명령을 실행시켜야 할 수도 있다. 이럴땐 Dockerfile에서 해당 계정을 만든뒤 USER 명령을 이용해서 해당 계정으로 바꾼다. 그러면 그 후에 실행되는 것은 해당 계정으로 실행하는 것이 된다. 


22. 현재 실행중인 컨테이너를 이미지로 만들어야 할 수 있다. 이미지로 제공되는 설정을 컨테이너로 실행되게 한 상태에서 해당 설정을 바꾸고 이를 이미지로 저장해서 재사용할 수도 있기 때문이다. 이럴때는 commit 명령을 이용한다. 예를 들어 wildfly란 이름의 컨테이너를 terry/wildfly 란 이미지로 저장하고자 할 때에는 docker commit -a "Terry Chang" wildfly terrychang/wildfly 로 명령을 실행한다. 이때 a 옵션은 이미지를 제작한 제작자를 설정하는 옵션이다.


23. 이미지를 특정 파일로 백업하고 특정 파일을 이미지로 복구할때 save/load 명령을 사용할 수 있다. 이와 비슷한 것으로 export/import 가 있다. 이 둘의 차이는 save/load는 그 대상이 이미지인것에 반해 export/import는 그 대상이 컨테이너(엄밀하게 말하면 export 명령을 이용해서 컨테이너를 특정 파일로 백업한뒤에 import를 이용해서 그 특정 파일을 이미지로 복구하는 것이다. 이 부분 헷갈리지 말도록)이다.

예를 들어 terrychang/wildfly란 이미지를 D:/dockerimages/customwildfly.tar 파일로 백업할때는 다음과 같이 한다.


docker save -o D:/dockerimages/customwildfly.tar terrychang/wildfly


이와는 반대로 D:/dockerimages/customwildfly.tar 파일을 terrychang/wildfly란 이미지로 복구할때는 다음과 같이 한다


docker load -i d:\dockerimages\customwildfly.tar


24. docker 이미지를 빌드할때는 빌드할때 필요한 파일들만 들어가 있는 디렉토리에 Dockerfile을 넣고 빌드해야 한다. 이게 나름 중요한데 Docker는 이미지를 빌드 할때 빌드명령이 실행된 디렉토리에 있는 모든 파일을 특정 공간에 업로드하고 사용한다. 이 과정을 몰라서 Dockerfile 파일을 가상 리눅스 머신 파일이 있는 곳에 넣고 빌드를 하다보니 빌드랄 할때 가상 리눅스 머신 파일이 같이 올라가면서 이 올라가는 과정만 계속 하다가 결국 뻗어버리는 증상이 있었다. 그래서 빌드를 할때는 Dockerfile 파일과 Dockerfile 안에서 빌드할때 사용되는 파일 및 디렉토리만 있게 하고 빌드 명령을 실행시켜야 한다.


25. centos나 ubuntu docker 이미지 파일의 경우 경량화(?)를 하는 이유로 백그라운드 서비스를 관리하는 systemd가 빠져있다. 그래서 centos의 경우는 centos에서 배포하는 centos/systemd 이미지를 사용하면 systemd를 이용한 백그라운드 서비스 관리를 이용할 수 있다. 이때 /usr/sbin/init 을 실행해야 한다. 이 init이 pid가 1이어야 systemd를 이용할 수 있다. 문제는 init을 실행하면서 별도 shell script(a.sh 라고 가정하자)를 실행해야 하는 상황이 있을수가 있는데 그럴때는 별도 shell script 파일(b.sh 라고 가정하자)을 만들고 이 파일에서 /usr/sbin/init과 a.sh가 실행이 되도록 하면 된다. 이때 주의할 점이 있는데 반드시 /usr/sbin/init 이 가장 마지막에 실행되도록 shell script를 만들어야 한다. 나는 pid가 1이어야 한다고 생각해서 /usr/sbin/init을 가장 먼저 실행되게끔 했는데 이렇게 하니까 b.sh가 실행이 되지 않는 문제가 발생하였다.  다음은 wildfly의 standalone.sh와 /usr/sbin/init이 실행되게끔 한 shell script 파일 소스이다.


#!/bin/bash

# background로 wildfly를 실행시킨다. 
# 원래는 /opt/jboss/wildfly/standalone/log/server.log 파일에 로그를 기록하지만 
# 별도 로그파일을 만들어서 보고 싶을 경우엔 
# /dev/null 부분을 특정 로그(ex: /usr/log/wildfly.log)로 지정하면 그 파일에 로그를 기록하게 된다

nohup /opt/jboss/wildfly/bin/standalone.sh -b 0.0.0.0 -bmanagement 0.0.0.0 > /dev/null &
exec /usr/sbin/init


26. 25번의 연장선상에 해당되는 설명인데 /usr/sbin/init을 실행할 경우 Dockerfile의 ENV를 이용해 설정한 환경변수가 이미지에 적용이 되지 않는다. 원래 ENV를 이용해서 환경변수를 설정하면 이것이 빌드할때 이미지에 반영되어 이 이미지를 컨테이너로 실행시킬때 해당 환경변수가 OS에 적용이 되는데 /usr/sbin/init이 실행되면 이 기능이 되지를 않는다(리눅스를 몰라서 구체적으로 설명하기는 어렵지만 구글링을 해보면 이 증상은 당연한 것이라고 나온다) 그래서 이와 같이 /usr/sbin/init이 실행되는 이미지가 컨테이너로 실행이 되는 상황에서 환경변수가 인식이 되게끔 할려면 /etc/environment 파일에 해당 환경변수가 기록이 되게끔 Dockerfile에 서술해주면 된다. 예를 들어 다음의 코드를 Dockerfile 안에 넣어주면..


RUN echo -e "LANG=ko_KR.utf8\nLC_ALL=\nJAVA_HOME=/opt/java" > /etc/environment


/etc/environment 파일이 다음과 같이 된다. 


LANG=ko_KR.utf8
LC_ALL=
JAVA_HOME=/opt/java


그러나 위의 내용은 Dockerfile을 통해 빌드를 해서 이미지를 만든뒤 컨테이너로 올려 실행할때의 발생되는 문제이지 Dockerfile에서 ENV로 설정한 환경변수를 빌드하는 과정에서 해당 환경변수를 이용할때는 문제가 없다. 예를 들어 ENV JAVA_HOME=/opt/java 로 했다고 가정할 경우 Dockerfile에서 이 환경변수를 이용하기 위해 RUN mv jdk* ${JAVA_HOME} 로 했을 경우 JAVA_HOME은 /opt/java로 인식되어 mv 명령을 수행하게 된다. 즉 빌드하는 과정에서 ENV로 설정한 환경변수를이용하는데는 문제가 없으니 오해없길 바란다.  


27. 25,26번의 연장선상에 해당되는 내용인데 26번에서 /usr/sbin/init을 실행하면 ENV로 설정한 환경변수가 이미지에 적용이 안되어 컨테이너에서 이 환경변수를 이용할 수 없다고 했다. 이런 문제때문에 환경변수를 이용해 지정하게 되는 PATH 또한 이 영향을 받게 된다. 이 부분을 해결할려면 /etc/profile.d 디렉토리에 별도의 shell script 파일이 생성되게끔 해서 컨테이너가 시작될때 이 shell script가 자동으로 실행이 되도록 한다. 예를 들어 Dockerfile에 ENV JAVA_HOME=/opt/java 을 넣고 다음의 코드를 Dockerfile에 넣어주면

 

RUN echo -e "export PATH=$PATH:$JAVA_HOME/bin" > /etc/profile.d/path.sh


빌드하는 시점에 $JAVA_HOME은 /opt/java로 인식이 되어 /etc/profile.d/path.sh 파일엔 export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/java/bin 가 들어가게 된다.


28. github에서 빌드 관련 파일들을 올려두고 Docker Hub와 연동해서 이미지 빌드 작업을 진행 할 경우 간혹 이런 메시지를 볼 수 있다


/assets/setup.sh: /bin/bash: bad interpreter: Text file busy


로칼에서 빌드할때는 이런 에러가 없었는데 Docker Hub로 연동해서 빌드할때 이런 에러 메시지가 나온다. 구글링을 한 바로는 이럴때 해당 shell 스크립트 파일을 실행하기 전에 sync 명령어를 실행하라고 해서 이 에러메시지를 잡았다. 

위의 에러 메시지가 나타나게 된 Dockerfile 코드를 예를 들어 구체적으로 설명하자면 에러 메시지가 나올당시의 Dockerfile 코드는 다음과 같이 되어 있었다


RUN chmod +x /assets/setup.sh && /assets/setup.sh


위의 코드를 다음과 같이 에러 메시지를 유발시키는 shell script(여기서는 /assets/setup.sh) 파일 앞에 sync를 추가로 넣어 실행이 되게끔 했다.


RUN chmod +x /assets/setup.sh && sync && /assets/setup.sh


이렇게 코드를 수정한뒤 빌드해서 에러 없이 빌드를 마쳤다


29. docker 컨테이너를 올리는 과정에서 다음의 에러 메시지를 docker logs 명령을 통해 확인되는 경우가 있다


standard_init_linux.go:195: exec user process caused “no such file or directory”


이 에러가 발생하는 상황이 딱히 정해져 있지는 않아서 지금 말하는 이 상황에서만 발생한다고 말할수는 없어보이나 나의 경우는 지금 말하는 이 상황에서만 발생하여서 이에 대해 정리를 하고자 한다.


docker 이미지를 만드는 과정에서 이런 저런 이유로 shell 파일들을 안에 넣게 되는데, 이때 shell 파일의 개행문자 처리 방식이 Windows일 경우 이 증상이 나타난다. 그래서 이럴땐 shell 파일의 개행문자 처리 방식을 Unix로 바꿔주면 된다.


Notepad++의 경우엔 shell 파일을 연뒤에 notepad++ 맨 밑에 우측을 보면 Windows (CR LF) 라고 나오는 부분이 있다. 이것은 개행문자를 Windows 형태 즉 \r\n의 초합으로 한다는것을 의미한다. 이 Windows (CR LF) 라고 나오는 부분을 마우스 우클릭하면 조그만 팝업 메뉴가 나타나는데 여기서 Unix 형식으로 변환 을 선택하면 개행문자 처리 방식을 Unix 형태 즉 \n 형태로 바꾸게 된다.


30. network와 관련하여 별도의 설정을 하지 않으면 docker container는 외부 인터넷 망에 대한 연결은 가능한 상태이지만 정작 docker를 운영하는 host와는 연결이 되지 않는 상태가 된다. 그래서 host와의 연결을 하기 위해 bridge 네트워크를 생성해야 할 필요성이 있다. 이럴때 다음과 같이 bridge network 를 생성한 뒤에 이를 이용하면 된다


docker network create -d bridge --subnet 192.168.100.0/24 --gateway 192.168.100.1 dockernet


docker network --help 하면 괸련 명령어의 설명을 볼 수 있는데 create는 생성할때 사용하는 명령이다 -d로 네트워크를 관리할 드라이버를 지정해야 하는데 여기엔 bridge와 overlay 이렇게 2개가 있다. 만약 container가 해당 container를 운영하는 host 및 그 host가 운영하는 container들 하고만 통신한다면 bridge 로 설정하면 된다. 그러나 이 container가 자신을 운영하는 host 뿐만 아니라 기타 다른 docker host 및 이 host가 운영하는 container들과 통신해야 한다면 이때는 overlay 로 설정한다(-d를 지정하지 않으면 default로 bridge로 설정된다) --subnet 과 --gateway는 이 생성된 network가 이용하게 될 ip 영역대와 gateway를 지정하게 된다. 위의 예시를 들어 설명한다면 192.168..100.2~255 번까지의 ip 주소들을 생성하고자 하는 network를 사용할 container가 자신의 ip 주소로 사용하게 되고, 이에 대한 gateway는 192.168.10.1을 사용하게 된다. 마지막으로 dockernet은 생성하게 되는 network의 이름을 지정하는 것이다. 이렇게 하면 docker network ls 명령을 이용해서 현재 생성된 network 들의 목록을 보게 될 때 dockernet 이란 이름으로 현재 생성한 network가 보이게 된다.


이렇게 network를 생성하게 되면 이제 이렇게 생성된 network를 docker container가 이용해서 사용하도록 해주어야 한다. 이것은 docker run을 이용해서 container를 실행시킬때 --net=dockernet 을 주어 docker container가 dockernet 네트워크를 이용하게끔 해주면 된다. 또 docker-compose 에서 이를 이용할땐 다음과 같은 방법으로 사용해주면 된다.


version: '2.1'


services:

  terrycentos:

    image: furywolf/centosprod

    container_name: centosprod

    cap_add:

      - SYS_ADMIN

    volumes:

      - /sys/fs/cgroup:/sys/fs/cgroup:ro

      - d:/docker/volumes/centos:/mnt/shared:rw

    ports:

      - "21:21"

      - "2122:22"

      - "64000-64010:64000-64010"

    networks:

      dockernet:

        ipv4_address: 192.168.100.200

networks:

  dockernet:

    external: true


services:terrycentos:와 같이 서비스명을 지정한 상태에서 하위에 networks란 멤버를 둔뒤에 여기에 사용하고자 하는 network인 dockernet을 지정한다. 그리고 networks:dockernet: 을 통해 해당 dockernet network를 지목한 상태에서 external: true를 줌으로써 docker host로의 접속이 허용이 되게끔 한다. docker run의 경우 host로의 접속이 허용되게 하는것은 기본 설정인데 만약 이를 막고자 할경우(host 접속하는 것을 막고자 하는 경우) --internal 옵션을 docker run 명령의 옵션으로 주면 된다


31. 30번의 경우는 container가 host로 접속을 하는 것에 해당하지만 host가 container가 가지고 있는 ip로의 접속이 된다는 뜻은 아니다. 그래서 이것을 하기 위해서는 이제부터 설명하게 될 설정을 해야 할 필요가 있다. 이 방법을 하면 30번에서 설명했던 container에서 host로의 연결도 같이 해결되기 때문에 30번에서 설명한 설정을 할 필요가 없다.

docker for windows 의 경우 container에 할당되는 ip는 192.168.100.X 형태의 내부 ip로 받게 되어 있다. 그러나 Windows 10에서 Network 관련 설정을 보면 docker와 관련된 ip 설정은 10.0.75.X 형태의 ip 설정만 존재하고 있다. 즉 192.168.100.X와 10.0.75.X와의 연결고리가 존재하지 않는 것이다. 그래서 이를 해결하기 위해 Windows 10 명령 프롬프트 창(CMD로 실행되는 명령 프롬프트창)을 관리자 권한으로 실행시킨 뒤 다음의 명령을 입력한다


route -p add 192.168.100.0 MASK 255.255.255.0 10.0.75.2


이렇게 입력하면 서로 다른 두 ip 영역대에 대한 연결관계가 성립이 되어 host와 container간의 ip로의 통신을 할 수 있게 된다(host에서는 container의 ip를 통한 통신이, container에서는 host의 ip를 통한 통신이 가능해진다)


위의 내용은 docker for windows에서 해당하는 내용이지 docker for mac이나 linux에서 운영중인 docker 에서도 사용가능한 방법인지는 확인되지는 않았다.


참고한 내용은 여기에서 했다(질문자인 whitecolor가 남긴 세번째 답변 글에서 참조했다)


중요 : 이걸 확인하려고 할때 ping을 이용해서 확인하면 안된다. docker conatainer 에서 host인 windows 로 통신여부를 체크할때는 ping을 써도 상관없지만 host인 windows에서 docker container로 통신여부를 체크할때는 ping을 사용하면 안된다. windows에서 port ping을 체크할 수 있는 프로그램인 tcping 을 다운받아서 특정 포트가 열려있는 컨테이너에서 포트에 대한 통신으로 체크하면 된다(ex : tcping 172.100.0.2 8080)


이것을 설정할 경우 개인적으로 가장 큰 장점이라 꼽히는 것은 container ip에 container port를 직접적으로 접근할 수 있다는 것이다. 예를 들어 우리가 container의 port를 이용하고자 할때 docker run 명령에서 -p 옵션을 사용하게 된다. -p 3080:8080 이렇게 주면 host의 3080 포트를 container의 8080 포트와 연결하는 것이다. 그래서 host ip:3080 하면 container의 8080 포트와 연결을 하게 되는 것이다. 그러나 container ip를 직접 접근할 수 있게 되면 container ip:8080 하는 식으로 host를 거치지 않고 container의 포트를 직접 접근할 수 있게 된다


※ 주의사항


처음 30번에서 설명한 route 설정을 할때 IP를 다음과 같이 설정했었다.


route -p add 172.0.0.0 MASK 255.0.0.0 10.0.75.2


이렇게 설정하니까 얼마 안있어 구글을 이용해서 검색을 하는데 문제가 생겼다. 계속 timeout이 걸렸는데..

이게 어떤때는 검색이 될 때도 있었고 되지 않는 때도 있어서 애를 좀 먹었다.

나중에 원인을 파악해보니 구글(www.google.co.kr) 도메인 주소가 DNS 서버를 통해 IP로 번역이 될때 172.217.160.67 이었는데..

route로 172로 시작하는 모든 IP 주소를 10.0.75.2로 연결하게끔하다보니..

구글 도메인 주소가 10.0.75.2를 통해 연결되는 상황이 벌어졌다.

이로 인해 검색이 되지 않는 문제가 생겼다.(검색이 되었을때의 IP 주소는 172로 시작하는 IP 주소가 아니었다)

그래서 docker container에 ip를 부여할때는 잘 알려지지 않고 사용하지 않는 IP 주소로 최소한의 범위로 route를 해주는게 좋다.

위에서와 같이 172.0.0.0 이런식으로 172로 시작하는 모든 주소 이런식으로 하지 말고..


route -p add 192.168.100.0 MASK 255.255.255.0 10.0.75.2


192.168.100 으로 시작하는 주소만 연결되게끔 하고 (MASK 설정도 IP 구성하는 4개 중 앞의 3개에 255를 설정하여 3개는 항상 고정이 되게끔 해준다)..

docker container가 사용할 네트워크도 위에서 설명한 것과 같이 192.168.100.0/24 이런 식으로 앞의 3개는 항상 고정되게끔 해주면 이런 상황을 피할수가 있다.

기존에 잘 되는 도메인 주소가 제대로 동작하지 않을때 해당 도메인 주소의 ip를 알아낸 뒤 이 ip가 docker 관련쪽으로 route 되는지 확인해보자


32. docker-compose.yml 파일에서 volume 항목을 다음과 같이 설정해야 할 때가 있다


/sys/fs/cgroup:/sys/fs/cgroup:ro


이것을 설정하는 이유는 systemctl 같은 서비스 기동/종료 명령을 사용하기 위해 설정하게 되는데 docker for windows 가 버전업이 되면서 docker-compose 명령 사용시 이 설정 부분에 에러가 발생하는 경우가 있다

이때는 windows 환경 변수의 시스템 변수에 COMPOSE_CONVERT_WINDOWS_PATHS 항목을 만들어 여기에 1을 설정해주면 해결된다





'프로그래밍 > Docker' 카테고리의 다른 글

Hyper-V에 CoreOS 설치하기(2)  (0) 2017.11.12
Hyper-V에 CoreOS 설치하기(1)  (0) 2017.11.12
docker에 대한 형식없는 정리  (0) 2017.07.19

트랙백을 확인할 수 있습니다

URL을 배껴둬서 트랙백을 보낼 수 있습니다

다른 카테고리의 글 목록

프로그래밍/Docker 카테고리의 포스트 목록을 보여줍니다