python flash 앱(oncall-bot)을 docker로 띄우려 할 때.. Dockerfile를 아래처럼 할 수 있다. 

FROM python:2.7-onbuild

EXPOSE 5000

ENTRYPOINT ["python"]
CMD ["oncall-bot.py"]



실행하는 방법은 다음과 같다. 


docker build -t oncall-bot:lastest .


docker run --rm -p 5000:5000 oncall-bot:lastest



로그도 잘 나온다. 




그러나 gunicorn을 사용할 때는 상황이 다르다. task 기반이라..



코드에 아래와 같이 handler를 추가한다. 

app = Flask(__name__)
app.logger.addHandler(logging.StreamHandler(sys.stdout))
app.logger.setLevel(logging.INFO)

함수 내에서 아래와 같이 사용한다. 

app.logger.info("-------------request.data-------------")
app.logger.info(request.data)

requirements.txt에 다음과 같이 gunicorn을 추가한다.

Flask
gunicorn
requests


Dockerfile에서는 아래와 같이 수정한다. 

FROM python:2.7-onbuild

EXPOSE 5000

CMD [ "gunicorn", "--workers", "4", "--bind", "0.0.0.0:5000", "--reload", "oncall-bot:app" ]


로그는 취합되어서 나온다. 


[~] docker logs 52a39cf13d4d

[2017-11-08 08:56:45 +0000] [1] [INFO] Starting gunicorn 19.7.1

[2017-11-08 08:56:45 +0000] [1] [INFO] Listening at: http://0.0.0.0:5000 (1)

[2017-11-08 08:56:45 +0000] [1] [INFO] Using worker: sync

[2017-11-08 08:56:45 +0000] [10] [INFO] Booting worker with pid: 10

[2017-11-08 08:56:45 +0000] [12] [INFO] Booting worker with pid: 12

[2017-11-08 08:56:45 +0000] [14] [INFO] Booting worker with pid: 14

[2017-11-08 08:56:45 +0000] [19] [INFO] Booting worker with pid: 19

-------------request.data-------------


Posted by '김용환'
,



docker container의 로그를 보려면 docker logs를 활용한다.


먼저 docker ps로 container id를 확인한다.


$ docker ps

CONTAINER ID        IMAGE                                                              COMMAND                  CREATED             STATUS              PORTS                      NAMES

3bfaccc746cc        dockerhub.google.com/excel/kami:develop   "/bin/sh -c 'target/u"   4 minutes ago       Up 4 minutes        0.0.0.0:10399->9000/tcp    kami-1


docker logs로 container log를 확인한다. 



$ docker logs 46817472b388

[info] application - Creating Pool for datasource 'default'

[info] p.a.d.DefaultDBApi - Database [default] connected at jdbc:mysql://1.1.1.1:3306/diction??autoReconnect=true&useSSL=false

[info] play.api.Play - Application started (Prod)

[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:9000



tail, 시간대역 별로도 볼 수 있다.


참조

https://docs.docker.com/engine/reference/commandline/logs/#usage




Posted by '김용환'
,

도커를 다시 하니 개념이 없어서 다시 개념을 잡기 위해서 무한 링크.. 


docker network, docker container, docker client cli, docker image, docker data volumns, docker rest api, docker daemon


출처 : https://docs.docker.com/engine/docker-overview/#what-can-i-use-docker-for




docker client, docker host, docker object, docker daemon, docker container, docker image, docker registry

출처 : https://docs.docker.com/engine/docker-overview/#the-docker-platform


namespace 


출처 : http://prog3.com/sbdm/blog/shlazww/article/details/47284675

https://success.docker.com/KBase/Introduction_to_User_Namespaces_in_Docker_Engine








veth, docker networking



출처 : http://www.linuxjournal.com/content/concerning-containers-connections-docker-networking








bridged, host mode, macvlan bridge mode, ipvlan mode 



출처 : http://www.abusedbits.com/2016/09/docker-host-networking-modes.html












libcontainer, libvirt, lxc, systemd-nspawn


출처: https://itechcraft.com/docker-containers-microservice-architecture/





aufs, lvm, zfs, rootfs, bootfs, 


출처 : https://image.slidesharecdn.com/bonamico-codemotion-docker-2014-2-141129035905-conversion-gate01/95/codemotiondocker2014-10-638.jpg?cb=1417233667




Posted by '김용환'
,


맥에서 도커 컨테이너 실행 시, 포트 연결이 안될 수 있다. 내부망 172.17.x.x 대역을 사용하는 환경에서 이슈가 존재한다. 도커는 디폴트로 172.17.0.0/16 대역을 사용하고 있다. 



gateway가 172.17.0.1이고 IPAddress가 172.17.0.2이라면 도커 컨테이너 실행시 포트 포워딩한다 해도 로컬 호스트에서 도커 포트로 연결이 안되는 문제가 발생된다. 


도커 기본 네트워크 환경을 변경한다. 다음 처럼 도커 기본 네트워크를 172.17.x.x. 대역이 아닌 192.168.x.x 대역으로 기본 구성을 변경한다. 


# cd ~/Library/Containers/com.docker.docker/Data/database

# git reset HEAD com.docker.driver.amd64-linux

Unstaged changes after reset:

D com.docker.driver.amd64-linux/disk/compact-after

D com.docker.driver.amd64-linux/disk/on-flush

D com.docker.driver.amd64-linux/disk/path

D com.docker.driver.amd64-linux/disk/size

D com.docker.driver.amd64-linux/disk/trim

D com.docker.driver.amd64-linux/etc/docker/daemon.json

D com.docker.driver.amd64-linux/etc/hostname

D com.docker.driver.amd64-linux/etc/ssl/certs/ca-certificates.crt

D com.docker.driver.amd64-linux/etc/sysctl.conf

D com.docker.driver.amd64-linux/expose-docker-socket

D com.docker.driver.amd64-linux/filesystem

D com.docker.driver.amd64-linux/hypervisor

D com.docker.driver.amd64-linux/insecure-registry

D com.docker.driver.amd64-linux/memory

D com.docker.driver.amd64-linux/memoryMiB

D com.docker.driver.amd64-linux/mounts

D com.docker.driver.amd64-linux/native/boot-protocol

D com.docker.driver.amd64-linux/native/port-forwarding

D com.docker.driver.amd64-linux/native/uefi-boot-disk

D com.docker.driver.amd64-linux/ncpu

D com.docker.driver.amd64-linux/network

D com.docker.driver.amd64-linux/on-sleep

D com.docker.driver.amd64-linux/proxy-system/exclude

D com.docker.driver.amd64-linux/proxy-system/http

D com.docker.driver.amd64-linux/proxy-system/https

D com.docker.driver.amd64-linux/proxy-verbose

D com.docker.driver.amd64-linux/proxy/exclude

D com.docker.driver.amd64-linux/proxy/http

D com.docker.driver.amd64-linux/proxy/https

D com.docker.driver.amd64-linux/proxy/mode

D com.docker.driver.amd64-linux/schema-version

D com.docker.driver.amd64-linux/slirp/dns

D com.docker.driver.amd64-linux/slirp/docker

D com.docker.driver.amd64-linux/slirp/domain

D com.docker.driver.amd64-linux/slirp/host

D com.docker.driver.amd64-linux/slirp/max-connections

D com.docker.driver.amd64-linux/slirp/mtu

D com.docker.driver.amd64-linux/state/last-shutdown-time

D com.docker.driver.amd64-linux/state/last-start-time

D com.docker.driver.amd64-linux/upgrade/experimental-debug

D com.docker.driver.amd64-linux/vmnet-simulate-failure


# git checkout -- com.docker.driver.amd64-linux


# vi com.docker.driver.amd64-linux/etc/docker/daemon.json

// {"debug":true,"experimental":true} 이렇게 되어 있는데.. 다음처럼 추가한다. 

{"debug":true,"experimental":true, "bip":"192.168.5.1/24"}



그 다음 Docker for mac 프로세스를 재시작한다. 



이제 확인해보자. 최신 docker를 사용 중인지 확인하고 테스트할 도커 이미지를 실행한다. 테스트할 도커 이미지는 springcloud/eureka이다. 



$ docker version

Client:

 Version:      17.09.0-ce

 API version:  1.32

 Go version:   go1.8.3

 Git commit:   afdb6d4

 Built:        Tue Sep 26 22:40:09 2017

 OS/Arch:      darwin/amd64


Server:

 Version:      17.09.0-ce

 API version:  1.32 (minimum version 1.12)

 Go version:   go1.8.3

 Git commit:   afdb6d4

 Built:        Tue Sep 26 22:45:38 2017

 OS/Arch:      linux/amd64

 Experimental: true

 





참고로 도커 컨테이너를 포그라운드 데몬하고 싶다면 다음 방식을 사용한다. 포트가 8761포트로 뜬 지 확인한다. 


이렇게 하면 포트 포워딩이 되지 않는다.


$ docker run springcloud/eureka

..

2017-10-20 02:35:42.958  INFO 1 --- [       Thread-4] c.n.eureka.PeerAwareInstanceRegistry     : Adding replica node: http://localhost:8761/eureka/

2017-10-20 02:35:43.025  INFO 1 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8761 (http)

2017-10-20 02:35:43.028  INFO 1 --- [           main] eurekademo.EurekaApplication             : Started EurekaApplication in 8.907 seconds (JVM running for 9.702)

2017-10-20 02:35:43.081  INFO 1 --- [       Thread-4] c.n.eureka.PeerAwareInstanceRegistry     : Updating the replica nodes as they seem to have changed from [] to [http://localhost:8761/eureka/]





-p 옵션을 주어야 동작할 수 있다. 8761포트를 8888포트로 연결할 마음으로  -p 8761:8888을 추가했다.

(따라하지 말고, 아래부터는 내용을 볼 것!!!)


$ docker run  -p 8761:8888  springcloud/eureka


-ti 옵션을 주면 조금 출력이 예뻐보인다. 


$ docker run  -p 8761:8888 -ti springcloud/eureka




백그라운드로 데몬을 실행하려면 다음을 사용한다. 


$ docker run  -p 8761:8888 -d springcloud/eureka




docker ps로 확인하니. 아래와 같이 나왔다. 



$ docker ps

CONTAINER ID        IMAGE                COMMAND                CREATED              STATUS              PORTS                              NAMES

a3938ad9745b        springcloud/eureka   "java -jar /app.jar"   About a minute ago   Up About a minute   8761/tcp, 0.0.0.0:8761->8888/tcp   focused_hopper




그러나 


8761, 8888 포트로 접근이 되지 않는다. 


$ curl localhost:8761/eureka/


$ curl localhost:8888/eureka/





확인해보기 위해 docker inspect를 실행해 보낟. 


$ docker inspect 도커-컨테이너-이름




네트워크만 보려면 다음 커맨드를 실행한다.  docker bridge 잘 있고. 네트워크도 192.168로 잘 설정되어 있다. 




$ docker network inspect bridge

[

    {

        "Name": "bridge",

        "Id": "13216e45817d9a5c15fffd0b77c732a65365129d49d1ed04fb8bbdc53c0ab348",

        "Created": "2017-10-27T06:33:11.783006123Z",

        "Scope": "local",

        "Driver": "bridge",

        "EnableIPv6": false,

        "IPAM": {

            "Driver": "default",

            "Options": null,

            "Config": [

                {

                    "Subnet": "192.168.5.1/24",

                    "Gateway": "192.168.5.1"

                }

            ]

        },

        "Internal": false,

        "Attachable": false,

        "Ingress": false,

        "ConfigFrom": {

            "Network": ""

        },

        "ConfigOnly": false,

        "Containers": {},

        "Options": {

            "com.docker.network.bridge.default_bridge": "true",

            "com.docker.network.bridge.enable_icc": "true",

            "com.docker.network.bridge.enable_ip_masquerade": "true",

            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",

            "com.docker.network.bridge.name": "docker0",

            "com.docker.network.driver.mtu": "1500"

        },

        "Labels": {}

    }

]





도커 컨테이너로 들어가도 잘 동작되는 것 같다. 


$ docker exec -it focused_hopper bash

root@6090234a5b33:/# 

root@6090234a5b33:/# ip addr

39: eth0@if40: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default

    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff

    inet 192.168.1.2/16 scope global eth0

       valid_lft forever preferred_lft forever

       



네트워크도 문제 없다. 

       

root@6090234a5b33:/# ip route

default via 172.17.0.1 dev eth0

172.17.0.0/16 dev eth0  proto kernel  scope link  src 172.17.0.2



내부에서 실행하면 동작이 잘된다. 


root@6090234a5b33:/#curl 172.17.0.2:8761

<!doctype html>

...





문제는 docker exec -p 옵션을 줄 때 반대로 주었다. 실제로 포트 포워딩할 포트가 앞에. 도커 컨테이너 포트는 뒤에 있어야 한다. 


docker -p "포트 포워딩할 포트:도커 컨테이너 포트" 이렇게 구성해야 한다. 이걸 모르고 삽질하고 있었다. 


다시 도커 컨테이너를 실행해본다. 



# docker run  -p 8888:8761 -d springcloud/eureka



# docker ps

CONTAINER ID        IMAGE                COMMAND                CREATED             STATUS              PORTS                    NAMES

75ba8624fff6        springcloud/eureka   "java -jar /app.jar"   6 seconds ago       Up 4 seconds        0.0.0.0:8888->8761/tcp   frosty_elion




# curl localhost:8888 하니 동작이 잘된다. 


docker port로 확인해보니 잘 동작한다. 


# docker port frosty_elion

8761/tcp -> 0.0.0.0:8888



lsof listen 포트 확인하니. 제대로 동작하는지 확인할 수 있었다. 


# lsof -iTCP -sTCP:LISTEN -n -P


vpnkit    21848 samuel.kim   20u  IPv4 0xb0df1cffacb7067      0t0  TCP *:8888 (LISTEN)

vpnkit    21848 samuel.kim   21u  IPv6 0xb0df1d003088737      0t0  TCP [::1]:8888 (LISTEN)





잘 동작한 것을 확인하고 도커 컨테이너를 내린다. 


$ docker stop frosty_elion




공부자료.

https://docs.docker.com/engine/userguide/networking/default_network/custom-docker0/

https://github.com/moby/moby/issues/25064

https://docs.docker.com/engine/reference/commandline/dockerd/




Posted by '김용환'
,

docker 내부에서 호스트 이름을 얻는 방법은 다음과 같다. 



# cat /etc/hostname

b84d97a03afc


# hostname

b84d97a03afc


# env  | grep HOSTNAME

HOSTNAME=b84d97a03afc




docker 내부에서 호스트 ip를 얻는 방법은 다음과 같다. 


$ ip addr

...

17: eth0@if18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default

    link/ether 02:42:c0:a8:05:02 brd ff:ff:ff:ff:ff:ff

    inet 192.168.5.2/24 scope global eth0

       valid_lft forever preferred_lft forever


# ip route  | grep src

192.168.5.0/24 dev eth0  proto kernel  scope link  src 192.168.5.2



Posted by '김용환'
,

[docker] aufs

docker 2017. 10. 19. 21:46


docker info 커맨드를 실행하면 다음 스토리지 드라이버로 aufs가 나타난다.  


...

Storage Driver: aufs

 Root Dir: /var/lib/docker/aufs

 Backing Filesystem: extfs

 Dirs: 98

 Dirperm1 Supported: true




docker의 내부 스택이 바로 aufs로 되어 있다.

(출처 : https://docs.docker.com)






따라서 docker containerization을 지원하는 형태는 mesos는 지원하는 당연히 aufs 파일 시스템을 지원한다. 

ubuntu랑도 docker가 잘 궁합이 맞는 것도 그런 드 하다. 



http://mesos.apache.org/documentation/latest/container-image/


AUFS

The reason AUFS is introduced is because overlayfs support hasn’t been merged until kernel 3.18 and Docker’s default storage backend for ubuntu 14.04 is AUFS.

Like overlayfs, AUFS is also a unioned file system, which is very stable, has a lot of real-world deployments, and has strong community support.

Some Linux distributions do not support AUFS. This is usually because AUFS is not included in the mainline (upstream) Linux kernel.

For more information of AUFS, please refer to here.


Posted by '김용환'
,



docker 로그인과 로그아웃을 사설 저장소 기반으로 연동할 수 있다. 


사설 저장소를 입력하지 않으면 index.docker.io 쪽으로 연동되니 주의할 필요가 있다. 



사설 저장소의 도커 로그인은 다음과 같다.

docker login dock.google.io


upload 쉘 스크립트에서 사용할 때는 다음과 같이 사용하면 좋을 것 같다.

docker login dock.google.io
if [ $? -ne 1 ]; then
echo "Please try again."
exit 1
fi


사설 저장소의 도커 로그아웃은 다음과 같다. 

docker logout dock.google.io



안타깝지만, 사설 저장송의 docker 로그인 여부는 확인할 수 없다.


기본 저장소(index.docker.io)일 때만 docker status로 확인할 수 있다. 





참고

https://docs.docker.com/engine/reference/commandline/login/

Posted by '김용환'
,


docker pull 하다가 ctrl+c를 눌러, 중지시켰다.

그리고, docker pull을 실행해도 다음 메시지만 출력하고 더 이상 pull을 하지 못할 수 있다.


.. already being pulled by another client. Waiting.



docker의 불안전한성(?) 때문인 것으로 생각되며, docker daemon을 재시작한다.


$ sudo service docker restart



docker daemon을 재시작한 후, docker pull하면 정상적으로 동작된다. 

Posted by '김용환'
,



지금까지 Dockfile를 만드록 Docker 컨테이너를 테스타했던 경험을 바탕으로 팁을 작성해본다.



1. 항상 Docker image는 최대한 작게 만들어야 한다.


처음 운영체제 Docker 이미지가 작더라도 조금씩 바이너리 또는 응용 프로그램을 설치하면 용량이 꺼진다. 


특히, yum update 또는 필요 없는 툴은 최대한 설치하지 않는다. 생각보다 툴은 용량을 많이 차지한다. 


용량이 꺼지면, 다음의 단점이 있다.

1. 배포를 해야 할 때, 다운로드해야 하기 때문에, 점점 속도가 느려진다.

2.용량이 크면 docker registry push 또는 docker hub push 할 때, 종종 에러가 발생할 수 있다. 계속 retry 해야 한다.. 

(아직 docker registry가 완벽하지 않다.)





2. Dockerfile 를 생성할 때는 설치 단위를 RUN 옵션으로 설정한다. 


Docker image는 history별로 layering이 되어 있다. 더 정확히 말하면, Dockerfile의 RUN 커맨드 하나가 history layer이다.  따라서 커맨드를 &&로 붙여 적당한 추상화를 할 수 있다.


apt-get update && apt-get install -y apache2 && apt-get clean && rm -rf /var/lib/apt/lists/*



docker history로 이미지를 보면, 마지막 컬럼이 SIZE이다. 내가 하는 모든 RUN에 대한 용량 체크를 할 수 있다. 



임시 파일/디렉토리 또는 /tmp 또는 wget으로 받은 압축 파일이 존재하는지 확인하고, 용량을 최대한 줄일 수 있도록 해야 한다. 





3. Docker image를 만들다 실패하더라도, 도커 이미지를 지우지 말고 다시 생성을 시도한다.


copy on write 방식이라, 기존에 쓰던 Docker image의 단계별 해시 정보가 있다면 바로 복사해서 쓰기 때문에, 최종 도커 이미지를 생성하기 전까지는 기존의 실패했던 이미지를 최대한 활용하는 방식이 좋다.



하지만, 앞 부분의 RUN 커맨드에서 변경이 일어나면, 뒷 부분까지 모두 해시 정보가 바뀔 수 있기 때문에 Dockerfile 전략을 잘 사용하는 것이 중요하다.


즉, Dockerfile에 새로운 설치를 추가할 때, 맨 마지막에 두어야 한다. 그 부분만 수정한 후, 다시 도커 이미지를 생성할 수 있기 때문에 빠르게 빌드할 수 있다. 





4. 도커 이미지 파일의 용량이 크다는 것은 그만큼 디스크와 CPU를 많이 소비할 수 있는 확률이 생길 수 있다.


Dockerfile을 최적화해도 용량이 늘어난다는 얘기는 계속 사용할 솔루션이 많다는 얘기이다.


8 cpu, 16G 장비에 4 GB가 안되는 도커 이미지를 컨테이너로 사용할 때, 거의 꽉차게 사용될 수 있다. 도커 이미지 특성상 부하가 많을 수 있기 때문에, 늘 테스트를 할 필요가 있다. 도커 컨테이너로 쓰일 장비를 늘 모니터링하고 좋은 장비를 사용하여 성능을 높일 수 있도록 노력해야 한다. 


Posted by '김용환'
,


docker 1.12부터 mac과 윈도우를 지원한다.


https://blog.docker.com/2016/07/docker-for-mac-and-windows-production-ready/


https://blog.docker.com/2016/07/docker-built-in-orchestration-ready-for-production-docker-1-12-goes-ga/



docker 1.12 rc4와 docker 1.12 정식 릴리즈를 쓰고 있는데, 정말 편하게 잘 테스트할 수 있어서 좋다.

Posted by '김용환'
,