큰 약속부터 시작하겠습니다. 당신은 오늘 이 기사를 절대적으로 좋아할 것입니다. 길고 상세하며 매우 유용할 것입니다. GRUB, GRUB2를 생각하십시오. 여기도 마찬가지입니다. LXC(Linux Containers) 기술을 간단하고 편리한 방식으로 래핑하는 멋진 배포 플랫폼인 Docker만 다룰 것입니다. 피>
시작하는 방법을 보여준 다음 SSH 및 Apache로 자체 컨테이너를 생성하고, Dockerfile 사용 방법을 배우고, 서비스 포트를 노출하고, 일반적으로 공개 포럼에서 절대 다루지 않는 엄청난 수의 작은 버그 및 문제를 해결합니다. . 더 이상 고민하지 말고 나를 따르십시오. 피>
피>
목차
<올 아이디="mozToc">
- 서비스 시작
- 아파치 서비스
- SSH 서비스
- 수신 포트 노출
- IP 주소 확인
- 새 구성 테스트
- 잠깐, 루트 암호가 무엇입니까? 리>
- 이미지 구축
- 테스트 이미지
- COPY 명령어
- exec와 첨부의 차이점
- 시작과 실행의 차이점
- 구축과 생성의 차이점
소개
나는 작년 언젠가 Gizmo의 프리웨어 기사에서 기술에 대한 간략한 개요를 제공했습니다. 이제 본격적으로 Docker 사용에 대해 알아보겠습니다. 먼저, 이 프레임워크를 사용하면 모든 작은 세부 사항에 대해 걱정할 필요 없이 편리한 방식으로 LXC를 사용할 수 있다는 점을 기억하는 것이 중요합니다. 이것은 OpenStack이 가상화 세계의 다음 진화 단계인 것과 같은 방식으로 이 세계의 다음 단계입니다. 몇 가지 역사와 비유를 드리겠습니다. 피>
가상화는 하드웨어를 추상화할 수 있는 소프트웨어에서 시작되었습니다. 그런 다음 속도를 높이기 위해 가상화 프로그램이 하드웨어 가속을 사용하기 시작했고 반가상화도 도입되었습니다. 결국 하이퍼바이저는 비가 내린 후 버섯처럼 나타나기 시작했고 모두 프로비저닝하고 관리하기가 다소 어려워졌습니다. 이것이 통합 API 아래에 다양한 플랫폼을 숨기는 OpenStack과 같은 개념의 핵심 이유입니다. 피>
컨테이너는 비슷한 방식으로 시작되었습니다. 첫째, 우리는 chroot를 가지고 있었지만 감옥에 갇힌 환경 내에서 실행되는 프로세스는 동일한 네임스페이스를 공유하고 동일한 리소스를 위해 싸웠습니다. 그런 다음 BIOS를 거치지 않고 다른 커널의 컨텍스트로 부팅할 수 있는 kexec 시스템 호출을 얻었습니다. 그런 다음 제어 그룹이 등장하여 CPU, 메모리 및 기타와 같은 시스템 리소스를 하위 그룹으로 분할하여 시스템에서 실행되는 프로세스를 더 잘 제어할 수 있게 되었습니다. 피>
나중에 Linux 커널은 기본 파티셔닝 메커니즘으로 cgroup을 사용하여 리소스의 완전한 격리를 제공하기 시작했습니다. 기술적으로 이것은 시스템 수준의 가상화 기술로, 자체 포함된 환경 내부의 제어 호스트 위에서 실행 중인 커널의 여러 인스턴스를 실행할 수 있으며 성능 저하 및 오버헤드가 거의 없습니다. 피>
몇몇 경쟁 기술은 OpenVZ와 같은 유사한 솔루션을 제공하려고 시도했지만 커뮤니티는 결국 메인라인 커널 내부의 기본 구현으로 초점을 좁혔고 이것이 미래 방향으로 보입니다. 여전히 LXC는 컨테이너를 실행하기 위해 상당한 양의 기술 지식과 스크립팅이 필요하기 때문에 사용하기 다소 어렵습니다. 피>
여기에서 Docker가 등장합니다. 복잡한 부분을 없애고 인프라 백엔드에 대한 걱정 없이 새 컨테이너 인스턴스를 생성하는 간단한 방법을 제공하려고 합니다. 음, 거의. 그러나 난이도는 훨씬 낮습니다. 피>
Docker의 또 다른 강력한 장점은 광범위한 커뮤니티 수용과 클라우드 서비스와의 통합에 대한 강조입니다. 여기서 우리는 전문 용어를 사용합니다. 즉, AWS, Hadoop, Azure, Jenkins 등과 같은 일부 주요 업체의 이름을 지정하는 것을 의미합니다. 그런 다음 PaaS(Platform as a Service)에 대해서도 이야기할 수 있으며 향후 몇 년 동안 이것이 얼마나 많은 돈과 초점을 맞출지 상상할 수 있습니다. 기술 환경은 방대하고 혼란스러우며 점점 더 많은 개념과 래퍼 기술이 도커 위에 구현되고 구축되면서 계속 변화하고 진화할 것입니다. 피>
그러나 우리는 기술적 측면에 집중하고 싶습니다. 일단 기본 사항을 마스터하면 강력한 통합 기능, 솔루션의 유연성을 천천히 확장하고 활용하기 시작하며 클라우드 에코시스템 전문 지식을 다양하고 자동화되며 순수한 수준으로 만들기 위해 노력할 것입니다. 지금 당장은 그런 일이 일어나지 않겠지만 처음 몇 마일, 또는 수 킬로미터라고 해야 진흙 투성이의 스타트업 물을 탐색하여 현명하고 효율적인 방식으로 Docker를 사용할 수 있도록 돕고 싶습니다. 이것은 젊은 기술이기 때문에 Wild West이며 대부분의 온라인 문서, 팁, 자습서 및 기타는 구식이며 누구에게도 도움이 되지 않는 복사 및 붙여넣기 버전이며 대체로 불완전합니다. 나는 오늘 그것을 고치고 싶다. 피>
도커 구현
우리가 멋진 일을 하기 전에 조금 더 지루한 일입니다. 어쨌든 Docker는 대부분 LXC에 관한 것이지만 LXC에 관한 것만은 아닙니다. 확장 가능하도록 설계되었으며 libvirt 및 systemd와 인터페이스할 수도 있습니다. 어떤 면에서 이것은 미래의 성장 가능성이 있기 때문에 거의 하이퍼 하이퍼바이저와 같게 만들고 추가 모듈이 추가되면 Xen이나 KVM 또는 libvirt와 친구들을 사용하는 모든 것과 같은 고전적인 하이퍼바이저를 효과적으로 대체할 수 있습니다. 피>
피>
궁금하다면 공개 도메인 이미지입니다. 피>
시작하기
Ubuntu가 아닌 CentOS 7을 사용하여 시연합니다. 대부분의 온라인 자료는 Ubuntu에 초점을 맞추고 있지만 가능한 한 기업에 가까운 Linux를 사용하여 수행되는 방법을 보여주고 싶습니다. Docker를 사용하려는 경우 비즈니스와 같은 곳이 될 것이기 때문입니다. 가장 먼저 할 일은 도커를 설치하는 것입니다:
얌 설치 도커-io
소프트웨어가 설치되면 사용을 시작할 수 있습니다. 그러나 docker 명령을 처음 실행하려고 하면 다음 두 가지 문제가 발생할 수 있습니다.
docker <하나의 명령>
FATA[0000] Get https:///var/run/docker.sock/v1.18/images/json:dial unix /var/run/docker.sock:no such file or directory. TLS 없이 TLS 사용 데몬에 연결하려고 합니까? 피>
다른 오류는 다음과 같습니다.
docker <하나의 명령>
FATA[0000] https:///var/run/docker.sock/v1.18/containers/json 가져오기:유닉스에 전화 걸기 /var/run/docker.sock:권한이 거부되었습니다. TLS 없이 TLS 사용 데몬에 연결하려고 합니까? 피>
그 이유는 Docker 서비스를 먼저 시작해야 하기 때문입니다. 또한 Docker는 다소 민감한 시스템 부분에 액세스하고 커널과 상호 작용해야 하기 때문에 이 기술을 루트로 실행해야 합니다. 그것이 작동하는 방식입니다. 피>
systemctl 시작 도커
이제 미친 듯이 Docker를 사용할 수 있습니다. 피>
도커 명령
기본적인 것은 docker help를 실행하여 사용 가능한 명령 목록을 얻는 것입니다. 나는 모든 옵션을 거치지 않을 것입니다. 진행하면서 그들에 대해 더 많이 알게 될 것입니다. 일반적으로 의심이 가는 경우 꽤 괜찮은 온라인 설명서를 참조해야 합니다. 전체 CLI 참조도 훌륭합니다. 그리고 GitHub에는 훌륭한 치트 시트도 있습니다. 그러나 첫 번째 임무는 새 Docker 이미지를 다운로드한 다음 첫 번째 인스턴스를 실행하는 것입니다. 피>
이미지 가져오기
사용 가능한 이미지가 많이 있습니다. 우리는 CentOS로 연습하고 싶습니다. 이것은 좋은 출발점입니다. 공식 리포지토리를 사용할 수 있으며 지원되는 모든 이미지와 태그가 나열되어 있습니다. 실제로 이 시점에서 Docker 이미지에 레이블이 지정되는 방식을 이해해야 합니다. 피>
명명 규칙은 저장소:태그(예:centos:latest)입니다. 즉, 최신 CentOS 이미지를 원합니다. 그러나 필수 이미지는 centos:6.6일 수도 있습니다. 좋아, 해보자. 피>
피>
이제 docker images 명령을 실행하여 이미지를 나열해 보겠습니다.
피>
Docker 컨테이너 시작
원래 자습서에서 본 것처럼 가장 간단한 예는 셸을 실행하는 것입니다.
도커 실행 -ti centos:centos7 /bin/bash
그래서 우리는 여기에 무엇을 가지고 있습니까? BASH 셸을 사용하여 CentOS 7 이미지에서 자체 TTY(-t) 및 STDIN(-i)을 사용하여 새 컨테이너 인스턴스를 실행하고 있습니다. 몇 초 안에 컨테이너 내부에 새로운 쉘이 생깁니다. 이제는 매우 기본적이고 간소화된 운영 체제이지만 내부에서 빌드를 시작할 수 있습니다. 피>
피>
피>
Apache 및 SSH 설치
SSH 액세스도 가능한 웹 서버를 설정해 보겠습니다. 이를 위해 다소 기본적인 설치를 수행해야 합니다. Apache(httpd) 및 SSHD(openssh-server)를 가져와 구성합니다. 이것은 본질적으로 Docker와 관련이 없지만 유용한 연습입니다. 피>
어떻게, 여러분 중 일부는 컨테이너 내부에 SSH가 필요하지 않으며 보안 위험 등이 있다고 외칠 수 있습니다. 필요한 것과 컨테이너를 사용하려는 목적에 따라 예 또는 아니오가 될 수 있습니다. 그러나 보안 고려 사항은 제쳐두도록 합시다. 연습의 목적은 모든 서비스를 설정하고 실행하는 방법을 배우는 것입니다. 피>
서비스 시작
init 스크립트 또는 systemd 명령을 사용하여 Apache를 시작할 수 있습니다. 이것은 제대로 작동하지 않을 것입니다. 특히 CentOS의 경우 systemd와 함께 제공되지만 더 중요한 것은 컨테이너에 자체 systemd가 없다는 것입니다. 시도하면 명령이 실패합니다. 피>
systemctl 시작 httpd
D-Bus 연결 실패:서비스 관리자에 대한 연결이 없습니다. 피>
이 문제에 대한 해킹이 있으며 향후 튜토리얼에서 이들 중 일부에 대해 배울 것입니다. 그러나 일반적으로 컨테이너의 가볍고 단순한 특성을 고려할 때 프로세스를 실행하기 위해 본격적인 시작 서비스가 실제로 필요하지는 않습니다. 이것은 약간의 복잡성을 추가합니다. 피>
아파치 서비스
Apache(HTTPD)를 실행하려면 배포판에서 /usr/sbin/httpd 또는 동등한 명령을 실행하기만 하면 됩니다. httpd.conf에서 ServerName 지시문을 구성하지 않았다는 경고와 함께 서비스가 시작되어야 합니다. 우리는 다소 광범위한 Apache 가이드에서 이를 수행하는 방법을 배웠습니다. 피>
/usr/sbin/httpd
AH00558:httpd:172.17.0.4를 사용하여 서버의 정규화된 도메인 이름을 안정적으로 확인할 수 없습니다. 이 메시지를 표시하지 않으려면 전역적으로 'ServerName' 지시문을 설정하십시오.
SSH 서비스
SSHD로 /usr/sbin/sshd를 실행합니다. 피>
/usr/sbin/sshd -f /etc/ssh/sshd_config
호스트 키를 로드할 수 없습니다:/etc/ssh/ssh_host_rsa_key
호스트 키를 로드할 수 없습니다:/etc/ssh/ssh_host_dsa_key
호스트 키를 로드할 수 없습니다:/etc/ssh/ssh_host_ecdsa_key
호스트 키를 로드할 수 없습니다:/etc/ssh/ssh_host_ed25519_key
모든 키를 가지지 못하기 때문에 실패할 수도 있습니다. 일반적으로 시작 스크립트는 이 작업을 수행하므로 서비스가 올바르게 시작되기 전에 ssh-keygen 명령을 한 번 실행해야 합니다. 두 명령 중 하나가 작동합니다:
/usr/bin/ssh-keygen -t rsa -f <파일 경로>
/usr/bin/ssh-keygen -A
ssh-keygen:새 호스트 키 생성:RSA1 RSA DSA ECDSA ED25519
웹 서버가 작동 중인지 확인
이제 컨테이너 내부에서 Apache가 실제로 실행되고 있음을 확인할 수 있습니다. 피>
ps -ef|grep 아파치
아파치 87 86 0 10:47 ? 00:00:00 /usr/sbin/httpd
아파치 88 86 0 10:47 ? 00:00:00 /usr/sbin/httpd
아파치 89 86 0 10:47 ? 00:00:00 /usr/sbin/httpd
아파치 90 86 0 10:47 ? 00:00:00 /usr/sbin/httpd
아파치 91 86 0 10:47 ? 00:00:00 /usr/sbin/httpd
하지만 외부 연결을 확인하려면 어떻게 해야 할까요? 이 시점에서 몇 가지 문제가 있습니다. 하나, 말하자면 열린 포트를 설정하지 않았습니다. 둘째, 컨테이너의 IP 주소가 무엇인지 모릅니다. 이제 BASH 셸 내에서 ifconfig를 실행하려고 하면 기본 네트워킹 명령을 포함하는 필수 패키지가 설치되지 않았기 때문에 어디에도 도달하지 못할 것입니다. 좋습니다. 컨테이너를 슬림하고 안전하게 만들 수 있기 때문입니다. 피>
수신 포트 노출
다른 웹 서버와 마찬가지로 들어오는 연결을 허용해야 합니다. 우리는 기본 포트 80을 사용할 것입니다. 이것은 방화벽 정책 등을 허용하는 라우터의 포트 포워딩과 다르지 않습니다. Docker를 사용하면 원하는 결과를 얻을 수 있는 여러 가지 방법이 있습니다. 피>
실행 명령으로 새 컨테이너를 시작할 때 -p 옵션을 사용하여 열 포트를 지정할 수 있습니다. 단일 포트 또는 포트 범위를 선택할 수 있으며 호스트 포트(hostPort)와 컨테이너 포트(containerPort)를 모두 매핑할 수도 있습니다. 예:
- -p 80은 컨테이너 포트 80을 노출합니다. 호스트의 임의 포트에 자동으로 매핑됩니다. 올바른 포트를 식별하는 방법은 나중에 배우게 됩니다. 리>
- -p 80:80은 컨테이너 포트를 호스트 포트 80에 매핑합니다. 즉, 컨테이너의 내부 IP 주소를 알 필요가 없습니다. Docker 가상 인터페이스를 통과하는 관련 내부 NAT 요소가 있습니다. 이에 대해 곧 논의하겠습니다. 또한 이 방법을 사용하면 하나의 컨테이너만 포트 80에 바인딩할 수 있습니다. 다른 IP 주소를 가진 여러 웹 서버를 사용하려면 각각 다른 포트에 설정해야 합니다. 리>
도커 실행 -ti -p 22:22 -p 80:80 이미지-1:최신
FATA[0000] 데몬의 오류 응답:컨테이너 64bd520e2d95a699156f5d40331d1aba972039c3c201a97268d61c6ed17e1619를 시작할 수 없습니다:0.0.0.0:80에 대한 바인딩 실패:포트가 이미 할당되었습니다.
많은 추가 고려 사항이 있습니다. IP 전달, 브리지된 네트워크, 공용 및 사설 네트워크, 서브넷 범위, 방화벽 규칙, 로드 밸런싱 등. 지금은 이러한 문제에 대해 걱정할 필요가 없습니다. 피>
포트를 노출하는 방법에 대한 추가 방법도 있지만 나중에 새 이미지를 빌드하기 위한 템플릿인 Dockerfiles 주제를 다룰 때 논의하겠습니다. 지금은 -p 옵션을 사용하여 이미지를 실행해야 한다는 것을 기억해야 합니다. 피>
IP 주소 확인
호스트 포트를 사용 가능한 상태로 두려면 hostPort 부분을 생략할 수 있습니다. 이 경우 IP 주소와 웹 서버 포트를 사용하여 컨테이너에 직접 연결할 수 있습니다. 이를 위해서는 컨테이너 세부 정보를 파악해야 합니다.
docker inspect <컨테이너 이름 또는 ID>
이것은 KVM XML 구성과 매우 유사한 매우 긴 세부 정보 목록을 제공합니다. 단, 이 구성은 데이터에 대한 또 다른 현대적이고 보기 흉한 형식인 JSON으로 작성됩니다. 읽을 수 있지만 매우 추합니다. 피>
도커 검사 산만_euclid
[{
"AppArmorProfile":"",
"인수":[],
"구성":{
"AttachStderr":참,
"AttachStdin":참,
"AttachStdout":참,
"명령":[
"/빈/배시"
],
"Cpu공유":0,
"Cpuset":"",
"도메인 이름":"",
"진입점":null,
"환경":[
...
"노출된 포트":{
"80/tcp":{}
},
"호스트 이름":"43b179c5aec7",
"이미지":"centos:centos7",
"레이블":{},
"MacAddress":"",
...피>
IP 주소만으로 범위를 좁힐 수 있습니다. 피>
docker inspect <컨테이너 이름 또는 ID> | grep -i "아이패드"
"IP 주소":"172.17.0.20",
새 구성 테스트
새로 시작합시다. 새 인스턴스를 시작하고 Apache를 설정하고 시작합니다. 웹 브라우저를 열고 테스트합니다. 작동한다면 웹 서버를 적절하게 구성한 것입니다. 정확히 우리가 원했던 것입니다. 피>
docker run -it -p 80:80 centos:centos7 /bin/bash
실행 중인 컨테이너를 확인하면 포트 매핑을 볼 수 있습니다. 간결함을 위해 출력이 여러 줄로 분할되었으므로 양해 바랍니다. 일반적으로 모두 대문자로 된 제목이 행 머리글로 표시되고 나머지는 한 줄에 하나의 컨테이너 아래에 인쇄됩니다. 피>
# 도커 ps
컨테이너 ID 이미지 명령
43b179c5aec7 centos:centos7 "/bin/bash"
생성됨 상태 포트
2시간 전 최대 2시간 0.0.0.0:80->80/tcp
이름 산만_유클리드
그리고 브라우저에서 다음을 얻습니다.
피>
옵션:이제 내부 IP 주소 범위는 호스트에서만 액세스할 수 있습니다. 다른 컴퓨터에서 액세스할 수 있도록 하려면 NAT 및 IP 전달이 필요합니다. 이름을 사용하려면 /etc/hosts와 DNS를 적절하게 구성해야 합니다. 컨테이너의 경우 새 인스턴스를 실행할 때 --add-host="host:IP" 지시문을 사용하여 이 작업을 수행할 수 있습니다. 피>
또 다른 참고 사항:다른 자습서에서 본 것처럼 Docker에는 VirtualBox 및 KVM과 매우 유사한 자체 내부 네트워킹이 있음을 기억하십시오. 상당히 광범위한 /16 네트워크이므로 상당한 자유가 있습니다. 호스트에서:
# /sbin/ifconfig
docker0:flags=4163
inet 172.17.42.1 넷마스크 255.255.0.0 브로드캐스트 0.0.0.0
inet6 fe80::5484:7aff:fefe:9799 prefixlen 64 범위 ID 0x20<링크>
에테르 56:84:7a:fe:97:99 txqueuelen 0 (이더넷)
RX 패킷 6199바이트 333408(325.5KiB)
RX 오류 0 드롭 0 오버런 0 프레임 0
TX 패킷 11037바이트 32736299(31.2MiB)
TX 오류 0 누락 0 오버런 0 이동통신사 0 충돌 0
SSH 작동 여부 확인
SSH를 사용하여 동일한 연습을 수행해야 합니다. 다시 말하지만 이것은 포트 22를 노출하는 것을 의미하며 몇 가지 옵션을 사용할 수 있습니다. 더 흥미롭게 만들기 위해 임의의 포트 할당을 시도해 보겠습니다.
도커 실행 -ti -p 20 -p 80 centos:centos7 /bin/bash
그리고 docker ps, 특히 포트에 대해 확인하는 경우:
0.0.0.0:49176->22/tcp, 0.0.0.0:49177->80/tcp 보링_mcclintock
즉, docker0 IP 주소, docker ps 명령 출력에 지정된 포트, 서비스 포트에서 실제로 컨테이너 IP에 직접 연결하는 것과 동일합니다. 이는 컨테이너가 사용하는 내부 IP 주소에 대해 걱정할 필요가 없고 전달을 단순화할 수 있기 때문에 유용할 수 있습니다. 이제 접속을 시도해보자. 호스트 포트를 사용하거나 컨테이너 IP를 직접 사용할 수 있습니다. 피>
SSH 172.17.42.1 -p 49117
어느 쪽이든 필요한 것을 얻을 수 있습니다. 예를 들면 다음과 같습니다.
SSH 172.17.0.5
호스트 '172.17.0.5(172.17.0.5)'의 신뢰성을 설정할 수 없습니다. ECDSA 키 지문은 00:4b:de:91:60:e5:22:cc:f7:89:01:19:3e:61:cb:ea입니다.
계속 연결하시겠습니까(예/아니오)? 예
경고:알려진 호스트 목록에 '172.17.0.5'(ECDSA)가 영구적으로 추가되었습니다.
[email protected]의 암호:
잠깐, 루트 암호가 무엇입니까?
루트 암호가 없기 때문에 실패합니다. 이제 우리는 무엇을 해야 합니까? 다시 말하지만 몇 가지 옵션이 있습니다. 먼저 passwd 명령을 사용하여 컨테이너 내부의 루트 암호를 변경해 보십시오. 하지만 passwd 유틸리티가 설치되어 있지 않기 때문에 작동하지 않습니다. 그런 다음 필요한 RPM을 가져와 컨테이너 내부에 설정할 수 있습니다. 호스트에서 종속성을 확인합니다.
rpm -q --/etc/passwd를 제공하는 것
설정-2.8.71-5.el7.noarch
그러나 이것은 보안 취약점입니다. 우리는 용기가 가늘기를 원합니다. 따라서 호스트의 /etc/shadow에서 컨테이너로 암호 해시를 복사할 수 있습니다. 나중에 좀 더 간소화된 방법에 대해 배우게 될 것입니다. 피>
아주 분명하게 치는 또 다른 사실은 우리가 모든 행동을 반복하고 있다는 것입니다. 이는 효율적이지 않으며 컨테이너에 수행한 변경 사항을 보존하려는 이유입니다. 다음 섹션에서 이를 처리합니다. 피>
피>
커밋 이미지
컨테이너를 변경한 후 커밋할 수 있습니다. 즉, 나중에 새 컨테이너를 시작할 때 처음부터 모든 단계를 반복할 필요가 없으며 기존 작업을 재사용하고 시간과 대역폭을 절약할 수 있습니다. ID 또는 별칭을 기반으로 이미지를 커밋할 수 있습니다.
docker commit <컨테이너 이름 또는 ID> <새 이미지>
예를 들어 다음을 얻습니다.
도커 커밋 43b179c5aec7 myapache3
1ee373ea750434354faeb1cb70b0177b463c51c96c9816dcdf5562b4730dac54
피>
피>
이미지 목록을 다시 확인하십시오:
피>
도커파일
이미지를 만드는 보다 간소화된 방법은 Dockerfile을 사용하는 것입니다. In a way, it's like using Makefile for compilation, only in Docker format. Or an RPM specfile if you will. Basically, in any one "build" directory, create a Dockerfile. We will learn what things we can put inside one, and why we want it for our Apache + SSH exercise. Then, we will build a new image from it. We can combine it with our committed images to preserve changes already done inside the container, like the installation of software, to make it faster and save network utilization. 피>
Before we go any further, let's take a look at a Dockerfile that we will be using for our exercise. At the moment, the commands may not make much sense, but they soon will. 피>
FROM myhttptest2:latest
EXPOSE 22
CMD ["/usr/sbin/sshd", "-D"]
EXPOSE 80
RUN mkdir -p /run/httpd
CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"]
여기에 무엇이 있습니까? 피>
- The FROM directory tells us what repo:tag to use as the baseline. In our case, it's one of the committed images that already contains the httpd and sshd binaries, SSH keys, and a bit more. 리>
- EXPOSE 22 - This line exposes port 22 inside the container. We can map it further using the -p option at runtime. The same is true for EXPOSE 80, which is relevant for the Web server. 리>
- CMD ["/usr/sbin/sshd", "-D"] - This instructions runs an executable, with optional arguments. 그만큼 간단합니다. 리>
- RUN mkdir -p /run/httpd - This instruction runs a command in a new layer on top of the base image - and COMMITS the results. This is very important to remember, as we will soon discuss what happens if you don't use the RUN mkdir thingie with Apache. 리>
- CMD ["/usr/sbin/httpd", "-D", "FOREGROUND"] - We run the server, in the foreground. The last bit is optional, but for the time being, you can start Apache this way. Good enough. 리>
As you can see, Dockerfiles aren't that complex or difficult to write, but they are highly useful. You can pretty much add anything you want. Using these templates form a basis for automation, and with conditional logic, you can create all sorts of scenarios and spawn containers that match your requirements. 피>
Build image
Once you have a Dockerfile in place, it's time to build a new image. Dockerfiles must follow a strict convention, just like Makefiles. It's best to keep different image builds in separate sub-directories. For example:
docker build -t test5 .
Sending build context to Docker daemon 41.47 kB
Sending build context to Docker daemon
Step 0 :FROM myapache4:latest
---> 7505c70235e6
Step 1 :EXPOSE 22 80
---> Using cache
---> 58f11217c3e3
Step 2 :CMD /usr/sbin/sshd -D
---> Using cache
---> 628c3d6b5399
Step 3 :RUN mkdir -p /run/httpd
---> Using cache
---> 5fc118f61a4d
Step 4 :CMD /usr/sbin/httpd -D FOREGROUND
---> Using cache
---> d892acd86198
Successfully built d892acd86198
The command tells us the following:-t repository name from a Dockerfile stored in the current directory (.). 그게 다야. Very simple and elegant.
피>
Test image
Run a new container from the created image. If everything went smoothly, you should have both SSH connectivity, as well as a running Web server in place. Again, all the usual network related rules apply. 피>
피>
Alternative build
Once you have the knowledge how do it on your own, you can try one of the official Apache builds. Indeed, the Docker repository contains a lot of good stuff, so you should definitely invest time checking available templates. For Apache, you only need the following in your Dockerfile - the second like is optional. 피>
FROM httpd:2.4
COPY ./public-html/ /usr/local/apache2/htdocs/
COPY instruction
What do we have above? Basically, in the Dockerfile, we have the declaration what template to use. And then, we have a COPY instructions, which will look for a public-html directory in the current folder and copy it into the container during the build. In the same manner, you can also copy your httpd.conf file. Depending on your distribution, the paths and filenames might differ. Finally, after building the image and running the container:
docker run -ti -p 22 -p 80 image-1:latest
AH00558:httpd:Could not reliably determine the server's fully qualified domain name, using 172.17.0.17. Set the 'ServerName' directive globally to suppress this message
[Thu Apr 16 21:08:35.967670 2015] [mpm_event:notice] [pid 1:tid 140302870259584] AH00489:Apache/2.4.12 (Unix) configured -- resuming normal operations
[Thu Apr 16 21:08:35.976879 2015] [core:notice] [pid 1:tid 140302870259584] AH00094:Command line:'httpd -D FOREGROUND'
피>
Advantages of containers
There are many good reasons why you want to use this technology. But let's just briefly focus on what we gain by running these tiny, isolated instances. Sure, there's a lot happening under the hood, in the kernel, but in general, the memory footprint of spawned containers is fairly small. In our case, the SSH + Apache containers use a tiny fraction of extra memory. Compare this to any virtualization technology. 피>
피>
피>
Problems you may encounter &troubleshooting
Let's go back to the Apache example, and now you will also learn why so many online tutorials sin the sin of copy &pasting information without checking, and why most of the advice is not correct, unfortunately. It has to do with, what do you do if your Apache server seems to die within a second or two after launching the container? Indeed, if this happens, you want to step into the container and troubleshoot. To that end, you can use the docker exec command to attach a shell to the instance. 피>
docker exec -ti boring_mcclintock /bin/bash
Then, it comes down to reading logs and trying to figure out what might have gone wrong. If your httpd.conf is configured correctly, you will have access and error logs under /var/log/httpd:
[auth_digest:error] [pid 25] (2)No such file or directory:AH01762:Failed to create shared memory segment on file /run/httpd/authdigest_shm.25
A typical problem is that you may be a missing /run/httpd directory. If this one does not exist in your container, httpd will start and die. Sounds so simple, but few if any reference mentions this. 피>
While initially playing with containers, I did encounter this issue. Reading online, I found several suggestions, none of which really helped. But I do want to elaborate on them, and how you can make progress in your problem solving, even if intermediate steps aren't really useful. 피>
Suggestion 1:You must use -D FOREGROUND to run Apache, and you must also use ENTRYPOINT rather than CMD. The difference between the two instructions is very subtle. And it does not solve our problem in any way. 피>
ENTRYPOINT ["/usr/sbin/httpd"]
CMD ["-D", "FOREGROUND"]
Suggestion 2:Use a separate startup script, which could work around any issues with the starting or restarting of the httpd service. In other words, the Dockerfile becomes something like this:
...
EXPOSE 80
COPY ./run-httpd.sh /run-httpd.sh
RUN chmod -v +x /run-httpd.sh
CMD ["/run-httpd.sh"]
And the contents of the run-httpd.sh script are along the lines of:
#!/bin/bash
rm -rf /run/httpd/*
exec /usr/sbin/apachectl -D FOREGROUND
Almost there. Remove any old leftover PID files, but these are normally not stored under /run/httpd. Instead, you will find them under /var/run/httpd. Moreover, we are not certain that this directory exists. 피>
Finally, the idea is to work around any problems with the execution of a separation shell inside which the httpd thread is spawned. While it does provide us with additional, useful lessons on how to manage the container, with COPY and RUN instructions, it's not what we need to fix the issue. 피>
Step 3 :EXPOSE 80
---> Using cache
---> 108785c8e507
Step 4 :COPY ./run-httpd.sh /run-httpd.sh
---> 582d795d59d4
Removing intermediate container 7ff5b58b40bf
Step 5 :RUN chmod -v +x /run-httpd.sh
---> Running in 56fadf4dd2d4
mode of '/run-httpd.sh' changed from 0644 (rw-r--r--) to 0755 (rwxr-xr-x)
---> 928640f680cf
Removing intermediate container 56fadf4dd2d4
Step 6 :CMD /run-httpd.sh
---> Running in f9c6b30795e2
---> b2dcc2818a27
Removing intermediate container f9c6b30795e2
Successfully built b2dcc2818a27
This won't work, because apachectl is an unsupported command for managing httpd, plus we have seen problems using startup scripts and utilities earlier, and we will work on fixing this in a separate tutorial. 피>
docker run -ti -p 80 image-2:latest
Passing arguments to httpd using apachectl is no longer supported. You can only start/stop/restart httpd using this script. If you want to pass extra arguments to httpd, edit the /etc/sysconfig/httpd config file. 피>
But it is useful to try these different things, to get the hang of it. Unfortunately, it also highlights the lack of maturity and the somewhat inadequate documentation for this technology out there. 피>
Additional commands
There are many ways you can interact with your container. If you do not want to attach a new shell to a running instance, you can use a subset of docker commands directly against the container ID or name:
docker
For instance, to get the top output from the container:
docker top boring_stallman
If you have too many images, some of which have just been used for testing, then you can remove them to free up some of your disk space. This can be done using the docker rmi command. 피>
# docker rmi -f test7
Untagged:test7:latest
Deleted: d0505b88466a97b73d083434b2dd0e7b59b9a5e8d0438b1bf8c6c
Deleted:5fc118f61bf856f6f3d90e0e71076b737fa7cc58cd56785ea7904
Deleted:628c3d6b53992521c9c1fdda4148693347c3d10b1d130f7e091e7
Deleted:58f11217c3e31206b4e41d07100a797cd4d17e4569b0fdb8b7a18
Deleted:7505c70235e638c54028ea5b63eba2b691de6bee67c2cb5e2861a
...
Then, you can also run your containers in the background. Using the -d flag will do exactly that, and you will get the shell prompt back. This is also useful if you do not mask signals, so if you accidentally break in your shell, you might kill the container when it's running in the foreground. 피>
docker run -d -ti -p 80 image-3:latest
You can also check events, examine changes inside a container's filesystem as well as check history, so you basically have a version control in place, export or import tarred images to and from remote locations, including over the Web, and more. 피>
Differences between exec and attach
If you read through the documentation, you will notice you can connect to a running container using either exec or attach commands. So what's the difference, you may ask? If we look at the official documentation, then:
The docker exec command runs a new command in a running container. The command started using docker exec only runs while the container's primary process (PID 1) is running, and it is not restarted if the container is restarted. 피>
On the other hand, attach gives you the following:
The docker attach command allows you to attach to a running container using the container's ID or name, either to view its ongoing output or to control it interactively. You can attach to the same contained process multiple times simultaneously, screen sharing style, or quickly view the progress of your daemonized process. You can detach from the container (and leave it running) with CTRL-p CTRL-q (for a quiet exit) or CTRL-c which will send a SIGKILL to the container. When you are attached to a container, and exit its main process, the process's exit code will be returned to the client. 피>
In other words, with attach, you will get a shell, and be able to do whatever you need. With exec, you can issue commands that do not require any interaction, but with you use a shell in combination with exec, you will achieve the same result as if you used attach. 피>
Differences between start and run
Start is used to resume the execution of a stopped container. It is not used to start a fresh instance. For that, you have the run command. The choice of words could have been better. 피>
Differences between build and create
The first command is used to create a new image from a Dockerfile. On the other hand, the latter is used to create a new container using command line options and arguments. Create lets you specify container settings, too, like network configurations, resource limitations and other settings, which affect the container from the outside, whereas the changes implemented by the build command will be reflected inside it, once you start an instance. And by start, I mean run. 알겠어? 피>
This is just a beginning ...
There are a million more things we can do: using systemd enabled containers, policies, security, resource constraints, proxying, signals, other networking and storage options including the super-critical question of how to mount data volumes inside containers so that data does not get destroyed when containers die, additional pure LXC commands, and more. We've barely scratched the surface. But now, we know what to do. And we'll get there. Slowly but surely. 피>
더 읽어보기
I recommend you allocate a few hours and then spend some honest time reading all of the below, in detail. Then practice. This is the only way you will really fully understand and embrace the concepts. 피>
My entire virtualization section
Dockerizing an SSH Deamon Service
Differences between save and export in Docker
Docker Explained:Using Dockerfiles to Automate Building of Images
결론
We're done with this tutorial for today. Hopefully, you've found it useful. In a nutshell, it does explain quite a few things, including how to get started with Docker, how to pull new images, run basic containers, add services like SSH and Apache, commit changes to a file, expose incoming ports, build new images with Dockerfiles, lots of troubleshooting of problems, additional commands, and more. Eventful and colorful, I'd dare say. 피>
In the future, we will expand significantly on what we learned here, and focus on various helper technologies like supervisord for instance, we will learn how to mount filesystems, work on administration and orchestration, and many other cool things. Docker is a very nice concept, and if used correctly, it can make your virtual world easier and more elegant. The initial few steps are rough, but with some luck, this guide will have provided you with the right dose of karma to get happily and confidently underway. Ping me if you have any requests or desires. Technology related, of course. We're done. 피> 추신 If you like this article, then you'd better give some love back to Dedoimedo!
건배. 피>