Curriculum
本文是 D瓜哥 学习 Docker Curriculum: A Docker Tutorial for Beginners 的一个随手笔记。内容略乱。
What is Docker?
Docker is a tool that allows developers, sys-admins etc. to easily deploy their applications in a sandbox (called containers) to run on the host operating system i.e. Linux.
The key benefit of Docker is that it allows users to package an application with all of its dependencies into a standardized unit for software development.
Why use containers?
Containers offer a logical packaging mechanism in which applications can be abstracted from the environment in which they actually run. This gives developers the ability to create predictable environments that are isolated from rest of the applications and can be run anywhere.
$ docker pull busybox
$ docker images
$ docker run busybox (1)
$ docker run busybox echo "hello from busybox"
$ docker ps
$ docker ps -a
$ docker container prune (2)
$ docker run -it busybox sh (3)
$ docker rm 305297d7a235 ff0a5c3750b9
$ docker rm $(docker ps -a -q -f status=exited) (4)
1 | When you call run, the Docker client finds the image (busybox in this case), loads up the container and then runs a command in that container. |
2 | 清除所有无用的 container。 |
3 | Running the run command with the ` ` flags attaches us to an interactive tty in the container. |
4 | This command deletes all containers that have a status of exited . |
One last thing that’ll be useful is the --rm
flag that can be passed to docker run
which automatically deletes the container once it’s exited from.
- Images
-
The blueprints of our application which form the basis of containers.
- Containers
-
Created from Docker images and run the actual application. A list of running containers can be seen using the
docker ps
command. - Docker Daemon
-
The background service running on the host that manages building, running and distributing Docker containers. The daemon is the process that runs in the operating system to which clients talk to.
- Docker Client
-
The command line tool that allows the user to interact with the daemon. More generally, there can be other forms of clients too - such as Kitematic which provide a GUI to the users.
- Docker Hub
-
A registry of Docker images. You can think of the registry as a directory of all available Docker images.
WEBAPPS WITH DOCKER
$ docker run -d -P --name static-site prakhar1989/static-site (1)
$ docker port static-site (2)
$ docker run -p 8888:80 prakhar1989/static-site (3)
$ docker stop static-site (4)
1 | -d will detach our terminal, -P will publish all exposed ports to random ports and finally --name corresponds to a name we want to give. |
2 | list port mapping |
3 | specify a custom port to which the client will forward connections to the container. |
4 | To stop a detached container, run docker stop by giving the container ID. |
You can also search for images directly from the command line using docker search
.
An important distinction to be aware of when it comes to images is the difference between base and child images.
-
Base images are images that have no parent image, usually images with an OS like ubuntu, busybox or debian.
-
Child images are images that build on base images and add additional functionality.
Then there are official and user images, which can be both base and child images.
-
Official images are images that are officially maintained and supported by the folks at Docker. These are typically one word long. In the list of images above, the
python
,ubuntu
,busybox
andhello-world
images are official images. -
User images are images created and shared by users like you and me. They build on base images and add additional functionality. Typically, these are formatted as
user/image-name
.
python:3-onbuild
. These images include multiple ONBUILD triggers, which should be all you need to bootstrap most applications. The build will COPY a requirements.txt
file, RUN pip install
on said file, and then copy the current directory into /usr/src/app
.
A Dockerfile is a simple text-file that contains a list of commands that the Docker client calls while creating an image.
# Instructions copied from - https://hub.docker.com/_/python/
FROM python:3-onbuild
# tell the port number the container should expose
EXPOSE 5000
# run the command
CMD ["python", "./app.py"]
$ git clone https://github.com/prakhar1989/docker-curriculum
$ cd docker-curriculum/flask-app
$ docker build -t diguage/catnip . (1)
$ docker run -p 8888:5000 diguage/catnip (2)
$ docker login (3)
$ docker push diguage/catnip (4)
1 | build image |
2 | run an image |
3 | logging into Docker Hub |
4 | pushing an image. Remember to replace the name of the image tag above with yours. |
$ docker pull docker.elastic.co/elasticsearch/elasticsearch:6.7.0 (1)
$ docker pull elasticsearch:6.7.0 (1)
$ docker run -d --name es -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:6.7.0 (2)
$ docker container ls
$ docker container logs es
$ curl 0.0.0.0:9200
1 | pull the image |
2 | run it in development mode by specifying ports and setting an environment variable that configures Elasticsearch cluster to run as a single-node. --name es to give our container a name |
# start from base
FROM ubuntu:latest
MAINTAINER Prakhar Srivastav <prakhar@prakhar.me>
# install system-wide deps for python and node
RUN apt-get -yqq update (1)
RUN apt-get -yqq install python-pip python-dev curl gnupg
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash
RUN apt-get install -yq nodejs
# copy our application code
ADD flask-app /opt/flask-app (2)
WORKDIR /opt/flask-app
# fetch app specific deps
RUN npm install
RUN npm run build
RUN pip install -r requirements.txt
# expose port
EXPOSE 5000
# start app
CMD [ "python", "./app.py" ]
1 | The yqq flag is used to suppress output and assumes "Yes" to all prompts. |
2 | We then use the ADD command to copy our application into a new volume in the container - /opt/flask-app . |
这个 Dockerfile ,还可以用 multi-images 优化一下。
|
$ git clone https://github.com/prakhar1989/FoodTrucks && cd FoodTrucks
$ docker build -t diguage/foodtrucks-web .
$ docker run -P --rm diguage/foodtrucks-web
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
c2c695315b3a bridge bridge local
a875bec5d6fd host host local
ead0e804a67b none null local
$ docker network inspect bridge
$ docker network create foodtrucks-net
The bridge network is the network in which containers are run by default.
$ docker container stop es
$ docker rm es
$ docker run -d --name es --net foodtrucks-net -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:6.7.0
docker run -it --rm --net foodtrucks-net diguage/foodtrucks-web bash
$ docker run -d --net foodtrucks-net -p 5000:5000 --name foodtrucks-web diguage/foodtrucks-web
On user-defined networks like foodtrucks-net, containers can not only communicate by IP address, but can also resolve a container name to an IP address. This capability is called automatic service discovery.
默认都是 bridge
,为什么第一次启动的时候连不上ES?
Docker Compose
Docker Compose - A tool for defining and running multi-container Docker applications.
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose --version
version: "3"
services:
es: (1)
image: elasticsearch:6.7.0 (2)
container_name: es
environment:
- discovery.type=single-node
ports: (3)
- 9200:9200
volumes: (5)
- esdata1:/usr/share/elasticsearch/data
web: (1)
image: diguage/foodtrucks-web (2)
command: python app.py (3)
depends_on: (6)
- es
ports: (3)
- 5000:5000
volumes: (4)
- ./flask-app:/opt/flask-app
volumes:
esdata1:
driver: local
1 | the names of our services |
2 | Docker image is required |
3 | Via other parameters such as command and ports we provide more information about the container. |
4 | The volumes parameter specifies a mount point in our web container where the code will reside. This is purely optional and is useful if you need access to logs etc. |
5 | the data we load persists between restarts. |
6 | start the es container before web . |
$ docker stop $(docker ps -q)
$ docker-compose up
$ docker-compose up -d
$ docker-compose ps
$ docker-compose down -v
$ docker network rm foodtrucks-net
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
3ab1281e0514 bridge bridge local
c2a88f94cbd7 host host local
228338a84116 none null local
$ docker-compose up -d
$ docker container ls
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
3ab1281e0514 bridge bridge local
0b45849b25ab foodtrucks_default bridge local
c2a88f94cbd7 host host local
228338a84116 none null local
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
22f4c483fc17 diguage/foodtrucks-web "python app.py" 11 minutes ago Up 11 minutes 0.0.0.0:5000->5000/tcp foodtrucks_web_1
564149dc1f34 elasticsearch:6.7.0 "/usr/local/bin/dock…" 11 minutes ago Up 11 minutes 0.0.0.0:9200->9200/tcp, 9300/tcp es
$ docker network inspect foodtrucks_default
$ docker-compose run web bash
version: "3"
services:
es:
image: elasticsearch:6.7.0
container_name: es
environment:
- discovery.type=single-node
ports:
- 9200:9200
volumes:
- esdata1:/usr/share/elasticsearch/data
web:
build: . # replaced image with build
command: python app.py
environment:
- DEBUG=True # set an env var for flask
depends_on:
- es
ports:
- 5000:5000
volumes:
- ./flask-app:/opt/flask-app
volumes:
esdata1:
driver: local
$ docker-compose up --build -d
# start from base
FROM ubuntu:latest
MAINTAINER Prakhar Srivastav <prakhar@prakhar.me>
# install system-wide deps for python and node
RUN apt-get -yqq update
RUN apt-get -yqq install python-pip python-dev curl gnupg
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash
RUN apt-get install -yq nodejs
# copy our application code
ADD flask-app /opt/flask-app
WORKDIR /opt/flask-app
# fetch app specific deps
RUN npm install --registry=https://registry.npm.taobao.org
RUN npm run build --registry=https://registry.npm.taobao.org
RUN pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ -r requirements.txt
# expose port
EXPOSE 5000
# start app
CMD [ "python", "./app.py" ]
中间构建过程,安装依赖是实在太过漫长。尝试切换了一下中国镜像,发现竟然很好用。
另外,构建过程中,有可能会报错。使用 docker container ls -a
找出异常退出的 container ID,然后使用 docker logs <containerID>
来查看错误信息。