一、docker命令
1. docker image 操作命令
- 查看系统所有image
sudo docker image ls (or) docker images
- 安装 ubuntu 14.04 image
sudo docker pull ubuntu:14.04
安装bitnami的wordpress imagesudo docker pull bitnami/wordpress
- 删除image
docker image rm [image ID] (or) docker rmi [image ID]
2. Dockerfile 编译
- 将Dockerfile 编译成 image
docker image build (or) docker build
- 在当前目录编译Dockerfile
docker build -t xiaopeng163/hello-world .
docker build --no-cache --rm --tag ${IMAGE_URI} -f Dockerfile .
- 查看image生成过程
docker history [image_ID]
3. 容器管理
- docker运行image
docker run xiaopeng163/hello-world
交互式运行ubuntu container -docker run -it ubuntu
- 表示进入containe的 shell中
docker run -it [image] /bin/bash
- 后台运行
docker run -d [image]
- 指定容器名字
docker run -d --name=demo laosuaidami/flask-hello-world
- 表示进入containe的 shell中
- 当前本地正在运行的程序
docker container ls
- 所有的容器,包括正在运行的,和已经退出的
docker container ls -a or docker ps -a
- 删除容器,包括正在运行的,和已经退出的
docker container rm [container_ID] (or) docker rm [container_ID]
docker container ls -aq (or) docker container ls -a|awk{'print$1'}
- 删除所有container
docker rm $(docker container ls -aq)
- 删除已经结束的container
docker rm $(docker container ls -f 'status=exited' -q)
- 修改container后变成新的image
docker container commit (or) docker commit
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
eg:docker commit quirky_chatelet hewei/centos-vim-f
- 进入正在运行的container中
docker exec -it [container id] [要执行的命令]
docker exec -it 05554595249d /bin/bash
docker exec -it 05554595249d python
docker exec -it 05554595249d ip a
打印运行的容器IP地址
- 停止容器
docker stop/start [container id (or) container name]
- 查看容器信息
docker inspect [container id (or) container name]
- 查看容器日志
docker logs [container id (or) container name]
- 查看安装logs
sudo docker logs mysql1
- 查看volume
sudo docker volume ls
- 删除volume
sudo docker volume rm [volume ID]
- 设置镜像标签
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
docker tag 6de222aa7640 xhy/centos7:v3 - 导出镜像
docker save -o centos-7.tar centos:7
- 导入镜像
docker load -i centos-7.tar
- 镜像管理
https://www.lagou.com/lgeduarticle/26246.html
https://www.moha.online/en/tutorial/docker/concise-user-guide
4. 查看官方命令文档
https://docs.docker.com/engine/reference/commandline/container/
5. docker hub 操作
1 登录退出docker hub docker login / docker logout
docker login 输入账号,密码
2. 将docker推送到docker hub docker push laosuaidami/hello-world:latest
3. 通过docker registry 搭建本地docker hub : https://hub.docker.com/_/registry
-
测试docker registry 是否搭建OK:
telnet [ ip ] [ port ]
yum install -y telnet
-
新建image 注意tag
docker build -t 192.168.10.159:5000/hello-world:latest
-
添加对本地docker registry 的信任 :
vi /etc/docker/daemon.json
加入以下内容{ "insecure-registries":["192.168.10.159:5000"] }
-
vi /lib/systemd/system/docker.service
添加一行EnvironmentFile=-/etc/docker/daemon.json
如下所示[Unit] Description=Docker Application Container Engine Documentation=https://docs.docker.com BindsTo=containerd.service After=network-online.target firewalld.service containerd.service Wants=network-online.target Requires=docker.socket [Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock EnvironmentFile=-/etc/docker/daemon.json # 添加这一行 ExecReload=/bin/kill -s HUP $MAINPID TimeoutSec=0 RestartSec=2 Restart=always
-
vi /etc/hosts
添加192.168.10.159 registry-1.docker.io
-
docker push 192.168.10.159:5000/hello-world
-
通过registry API 查看registry 中image :https://docs.docker.com/registry/spec/api/#listing-repositories
http://192.168.10.159:5000/v2/_catalog
结果如下{ repositories: [ "hello-world", "test_cmd", "ubuntu" ] }
二、Dockerfile 语法
FROM
FROM scratch # 制作base image 重开始制作,没有依赖基础镜像
FROM centos # 使用base image
FROM ubuntu:14.04
尽量使用官方的image作为base image
LABEL
LABEL maintainer="xiaoquwl@gmail.com"
LABEL version="1.0"
LABEL description="This is description"
类似代码注释
RUN
每运行一次RUN 都会增加新的分层,所以复杂的RUN请用反斜线换行!避免无用分层,合并多条命令成一行
RUN yum update && yum install -y vim \
python-dev # 反斜线换行
RUN apt-get update && apt-get instll -y perl\
pwgen --no-install-recommends && rm -rf \
/var/lib/apt/lists/* # 注意清理cache
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
WORKDIR
使用WORKDIR, 不要用 RUN cd! 尽量使用绝对目录!
WORKDIR /root
WORKDIR /test # 如果没有会自动创建test目录
WORKDIR demo
RUN pwd # 输出结果应该是 /test/demo
ADD and COPY
ADD hello /
ADD test.tar.gz / # 添加的根目录并解压
WORKDIR /root
ADD hello test/ # root/test/hello
WORKDIR /root
COPY hello test/
大部分情况, COPY 优于 ADD
ADD 除了 COPY 还有额外功能(解压)!
添加远程文件/目录请使用curl或者wget !
ENV
ENV MYSQL_VERSION 5.6 # 设置常量
RUN apt-get install -y mysql-server="${MYSQL_VERSION}" && rm -rf /var/lib/apt/lists/* # 引用常量
尽量使用,增加可维护性
VOLUME and EXPOSE (存储和网络)
CMD and ENTRYPOINT
RUM: 执行命令并创建新的Image Layer
CMD: 设置容器启动后默认执行的命令和参数
ENTRYPOINT: 设置容器启动时执行的命令
eg:
ENTRYPOINT ["/usr/bin/stress"] 这是执行的命令
CMD ['--verbose'] 这是执行的参数 可以外部输入 也可以设置默认 参数
Shell 和 Exec格式
-
Shell格式
RUN apt-get install -y vim CMD echo "hello docker!!" ENTRYPOINT echo "hello docker"
-
Exec格式
RUN [ "apt-get", 'install', "-y", "vim" ] CMD [ "/bin/echo", "hello docker" ] ENTRYPOINT [ "/bin/echo", "hello docker!!" ]
-
使用例子:
FROM centos ENV name Docker ENTRYPOINT echo "hello $name"
启动容器返回结果:
hello Docker
FROM centos ENV name Docker ENTRYPOINT ["/bin/echo", "hello $name"]
启动容器返回结果:
hello $name
FROM centos ENV name Docker ENTRYPOINT ["/bin/bash", "-c", "echo hello $name"]
启动容器返回结果:
hello Docker
CMD
- 容器启动时默认执行的命令
- 如果docker run 指定了其他命令, CMD 命令被忽略
- 如果定义了多个CMD, 只有最后一个会执行
例子:
FROM centos
ENV name Docker
CMD echo "hello $name"
# CMD echo "hello again!!"
启动容器命令:docker run [image]
输出 hello Docker
启动容器命令:docker run -it [image] /bin/bash
CMD 命令被忽略, 不会执行
ENTRYPOINT
- 让容器以应用程序或者服务的形式运行
- 不会被忽略,一定执行
- 最佳实践:写一个shell 脚本作为entrypoint
例子:
COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
例子:
容器接收命令行参数 ENTRYPOINT + CMD
FROM 192.168.10.159:5000/ubuntu
RUN apt-get update && apt-get install -y stress
ENTRYPOINT ["usr/bin/stress"]
CMD [] # 可以接收命令行输入参数
执行命令行:docker run -it hehe/ubuntu_stress --vm 1 --verbose
输出:
[root@localhost ubunt_stress_test]# docker run -it hehe/ubuntu_stress --vm 1 --verbose
stress: info: [1] dispatching hogs: 0 cpu, 0 io, 1 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogvm worker 1 [6] forked
stress: dbug: [6] allocating 268435456 bytes ...
stress: dbug: [6] touching bytes in strides of 4096 bytes ...
stress: dbug: [6] freed 268435456 bytes
三、容器的资源限制
1. 限制内存 --memory=xxxM
docker run --memory=200M laosuaidami/docker-stress --vm 1 --verbose --vm-bytes 500M
2. 限制cpu占用权重 --cpu-shares=10
docker run --cpu-shares=10 --name=test1 laosuaidami/docker-stress --cpu 1
docker run --cpu-shares=5 --name=test2 laosuaidami/docker-stress --cpu 1
四、docker网络
单机
- Bridge Network
- Host Network
- None Network
多机
- Overlay Network
1. Linux 创建 network namespace 并将其连通
1. docker run -d --name=test1 busybox /bin/sh -c "while true; do sleep 3600; done"
2. ip a 在shell中查看IP
3. sudo ip netns list # 查看network的namespace
4. sudo ip netns delete [namespace] 删除network namespace
5. 创建network namespace
1. sudo ip netns add test1
2. sudo ip netns add test2
6. sudo ip netns exec [namespace/ test1] ip a 查看network namespace ip
7. ip link 查看IP链接
8. sudo ip netns exec [namespace/ test1] ip link set dev lo up 启动 network namespace lo 网络链接
9. sudo ip link add veth-test1 type veth peer name veth-test2 添加一对veth link
10. 添加link到network namespace
1. sudo ip link set veth-test1 netns test1
2. sudo ip link set veth-test2 netns test2
11. 分别给test1 test2 分配IP地址
1. sudo ip netns exec test1 ip addr add 192.168.1.1/24 dev veth-test1
2. sudo ip netns exec test2 ip addr add 192.168.1.2/24 dev veth-test2
12. 启动 network namespace lo 网络链接
1. sudo ip netns exec test1 ip link set dev veth-test1 up
2. sudo ip netns exec test2 ip link set dev veth-tes2 up
13. 测试网络的连通性
1. sudo ip netns exec test1 ping 192.168.1.2
2. sudo ip netns exec test2 ping 192.168.1.1
14. 创建网络
docker network create [OPTIONS] NETWORK
eg: sudo docker network create -d overlay demo # -d, --driver string-->Driver to manage the Network (default "bridge")
Linux Network Namespace 网络连接图
2. docker network namespace & docker bridge0
1. docker network ls 查看docker网络network 信息
2. sudo docker network inspect [network id] 查看network的信息(可查看network上桥接的ip)
- sudo docker network inspect 5bb68053a8c3
3. sudo docker exec test1 ip a 查看test1容器的IP信息
4. brctl show 显示Linux网桥 sudo yum install bridge-utils
Docker Bridge Network 连接图
3. docker容器之间的link, 通过名字访问docker,不需要ip : --link test1
1. 先创建test1容器,在创建test2容器 并让test2链接到test1上
1. docker run -d --name=test1 busybox /bin/sh -c "while true; do sleep 3600; done"
2. docker run -d --name=test2 --link test1 busybox /bin/sh -c "while true; do sleep 3600; done"
3. 测试一下(可以用test1 代替 test1 container的ip)
1. sudo docker exec -it test2 /bin/sh 进入test2的shell
2. ping test1 测试能否ping通
3. test1:3306 即可访问MySQL数据库
2. link有方向性
4. 自己新建一个bridge 网络
1. 新建bridg:
sudo docker network create -d bridge my-bridge
2. 创建container时指定bridge: --network my-bridge
docker run -d --name test3 --network my-bridge busybox /bin/sh -c "while true; do sleep3600; done"
3. 给已经创建的container更换bridge
docker network connect my-bridge test2 test2 会同时连接到bridge和my-bridge
4. 如果两个container同时连接到一个用户自己定义的bridge时, 这两个container默认是相互link,即可以通过container name 代替 ip进行相互访问
5. container 的端口映射
1. 创建Nginx容器
1. docker run --name web -d nginx
2. 进入容器bash
1. docker exec -it web /bin/bash
3. 停止并删除web container
1. docker stop web
2. docker rm web
5.1 container 的端口映射 -p 80:80 (容器外端口:容器内端口)
1. docker run --name web -d -p 80:80 nginx
[外链图片转存失败(img-C85VrrUZ-1563492635696)(https://i.imgur.com/zYRzYeQ.png)]
6. host 和 none 网路模式
1. host: --network host 当前容器和主机共用ip和mac
docker run -d --name test1 --network host busybox /bin/sh -c "while true; do sleep3600; done"
2. none: --network none 当前容器没有ip和mac
docker run -d --name test1 --network none busybox /bin/sh -c "while true; do sleep3600; done"
7. 多容器的复杂部署
redis 和 服务分开部署,试验代码chapter4/flask-redis
给容器添加环境变量,-e PENG=value
1. 启动redis container
1. sudo docker run -d --name redis redis
2. 编译Docker,并启动container, -e 设置环境变量
1. sudo build -t laosuaidami/flask-redis .
2. sudo docker run -d --link redis --name flask-redis -e REDIS_HOST=redis laosuaidami/flask-redis
3. 进入container bash 中查看
1. docker exec -it flask-redis /bin/bash
2. 在bash中输入env 可以看到 REDIS_HOST=redis
3. 在bash中输入 curl 127.0.0.1:5000 可以访问服务
4. 重启 flask-redis ,先停止后关闭再重启
1. 重启命令加 -p 5000:5000 绑定本地端口
8. 多机通信
- 创建overlay 网络, 跨设备通信
eg: sudo docker network create -d overlay demo
https://blog.youkuaiyun.com/guohewei123/article/details/101481253
五、数据持久化
1. Docker持久化数据的方案
-
基于本地系统的volume。可以在执行Docker create 或 Docker run 时,通过 -v 参数将主机的目录作为容器的数据卷。这部分功能便是基于本地文件系统的volume管理。
-
基于plugin的Volume, 支持第三方的存储方案,比如 NAS , aws
2. Volume的类型
- 受管理的data Volume, 由docker后台自动创建。
- 绑定挂载的Volume,具体挂载位置可以由用户指定
3. Date Volume方法:创建MySQL container (Dockerfile: VOLUME /var/lib/mysql)
第一步:VOLUME ["/var/lib/mysql"]
or VOLUME /var/lib/mysql
第二步:docker run -v mysql_volume:/var/lib/mysql
1. sudo docker run -d --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
2. docker volume ls / docker volume rm [volume name] / docker volume inspect 查看/删除 volume
3. volume起别名(若别名存在则使用已有数据库): -v 别名:/var/lib/mysql # -v 别名:容器内部volume路径(如下图所示)
1. sudo docker run -d -v mysql_test:/var/lib/mysql --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql
4. Bind Mouting方法:docker run -v /home/aaa:/root/aaa
不需要在 Dockerfile 中定义 VOLUME ,只需指定容器内外对应关系。 -v 容器外地址:容器内地址
相当于共享文件夹 开发利器 便于调试容器内的代码,本地修改即可实现
docker run -d -v $(pwd):/usr/share/nginx/html -p 80:80 --name web laosuaidami/my-nginx
七、容器编排:Swarm mode
[外链图片转存失败(img-6UZdvzog-1563492635698)(https://i.imgur.com/3YDQsyA.png)]
[外链图片转存失败(img-ZOQYcmMY-1563492635698)(https://i.imgur.com/ZHq3mpN.png)]
[外链图片转存失败(img-umOoomu5-1563492635699)(https://i.imgur.com/COPgHvu.png)]
[外链图片转存失败(img-X2jjQyaq-1563492635699)(https://i.imgur.com/GvPRnJH.png)]
搭建 3 nodes swarm cluster setup
1. Vagrant + Virtualbox
1. 先初始化manager的cluster,宣告地址
1. docker swarm init --advertise-addr=192.168.205.10
2. 添加worker到manage cluster
1. docker swarm join --token SWMTKN-1-5zj189y4mz8yttawc6jlq1vb86hcu4lbzzo1nts1yzu7d9teaa-7g0w1oyppjynrqki1zy1pk3xi 192.168.205.10:2377
2. Docker Machine + Virtualbox
1. docker-machine creat swarm-manager
2. docker-machine creat swarm-work1
3. docker-machine creat swarm-work2
4. 之后和Vagrant + Virtualbox的方法一样了
3. Play with docker https://labs.play-with-docker.com/
Swarm 命令
1. docker swarm init --advertise-addr=192.168.205.10 # 先初始化cluster,宣告地址,让其他节点指定此节点的存在
2. docker node ls # list nodes in the swarm
3. 创建service
docker service create [OPTIONS] IMAGE [COMMAND] [ARG...]
eg: docker service create --name demo busybox sh -c "while true; do sleep 3600; done"
4. 查看service
docker service ls
5. 查看service在那台设备上
docker service ps [service name]
eg: docker service ps demo
6. docker service scale # 横向扩展,平均分配在各节点上 ,service container被删除后,会自动重启,平均分布在各cluster上
docker service scale SERVICE=REPLICAS [SERVICE=REPLICAS...]
eg: docker service scale dome=5 平均部署到各节点上
7. 删除service
ocker service rm SERVICE [SERVICE...]
eg: docker service rm demo
1. mysql + wordpress + swarm 在swarm集群里通过service部署wordpress
1. 创建overlay network
1. docker network create -d overlay demo # 创建名为demo的overlay网络
2. 创建 MySQL service
sudo docker service create --name mysql --env MYSQL_ROOT_PASSWORD=root --env MYSQL_DATABASE=wordpress --network demo --mount type=volume,source=mysql-date,destination=/var/lib/mysql mysql:5.7
3. 创建 WordPress service
sudo docker service create --name wordpress --env WORDPRESS_DB_PASSWORD=root --env WORDPRESS_DB_HOST=mysql -p 80:80 --network demo wordpress
2. 集群服务间通信之RoutingMesh
[外链图片转存失败(img-pJoLlAes-1563492635700)(https://i.imgur.com/AwEJWIN.png)]
2.1 Internal 方式
1. 创建overlay network
docker network create -d overlay demo # 创建名为demo的overlay网络
2. 创建 whoami service
1. docker service create --name whoami -p 8000:8000 --network demo -d jwilder/whoami
2. docker service create --name client -d --network demo busybox sh -c "while true; do sleep 3600; done"
3. 进入 client container shell 中:
1. ping whoami # 结果ip为 10.0.0.7
2. 通过 docker service scale whoami=3 开启多个whoami container后,ping whoami 结果仍然为 10.0.0.7
3. 在 client container 中运行 nslookup tasks.whoami 发现有3个ip 10.0.0.15~10.0.0.17,
4. 由此可见 10.0.0.7 是一个虚拟ip,他只和server name 相关
4. 通过VIP多次访问请求whoami会发现轮流出现container id ,其实内部自带负载均衡,主要需要使用虚拟ip访问才行
5. LVS--> Linux virtual Server lvs + keepalived 配置一个高可用的负载均衡
LVS–> Linux virtual Server 详见官方文档
[外链图片转存失败(img-EqqILqqi-1563492635700)(https://i.imgur.com/lw8Ehv1.png)]
[外链图片转存失败(img-zewLnz12-1563492635700)(https://i.imgur.com/OGayy2y.png)]
2.2 Ingress Network 方式
试验环境和2.1一样,在各个note server shell 运行:curl 127.0.0.1:8000, 会发现返回不同container id
1. 查看转发规则运行命令:sudo iptables -nL -t nat
2. brctl show 显示Linux网桥 sudo yum install bridge-utils
3. docker network inspect docker_gwbridge # 查看'ingress-sbox'ip
4. sudo ls /var/run/docker/netns 查找'ingress-sbox'文件
5. sudo nsentre --net=/var/run/docker/netns/ingress-sbox 进入'ingress-sbox'文件
6. ip a # 查看ip
1. 查看防火墙 iptables -nL -t mangle
2. sudo yum install ipvsadm 使用命令 ipvsadm -l
[外链图片转存失败(img-sKeq541F-1563492635700)(https://i.imgur.com/jDaKJbh.png)]
[外链图片转存失败(img-d2cpPhxG-1563492635701)(https://i.imgur.com/7XdCPeS.png)]
3. DockerStack 部署wordpress
1. 运行yml文件, docker stack deploy [OPTIONS] STACK
eg: docker stack deploy -c=docker-compose.yml wordpress
2. 查看stack
eg: docker stack ls
3. 查看stack的具体细节
eg: docker stack ps wordpress
4. 查看stack services
eg: docker stack services wordpress
4. Docker Secrets Managment
方法一:创建secrete
1. 新建文件将密码写入其中:假如文件名叫password
2. 创建secrete: docker secret create [OPTIONS] SECRET [file|-], 注意此步完成后可以删除password文件了!!!
eg: docker secret create my-pw password
3. 查看 secrete:
eg: docker secret ls
方法二:创建secrete
1. 命令行创建 secret:
echo "root" | docker secret create my-pw2 -
2. 删除secret
docker secret rm my-pw2
使用 secrete
1. 创建docker service create 使用--secret指定secret # Specify secrets to expose to the service
eg: docker service create --name demo --secret my-pw busybox sh -c "while true; do sleep 3600; done"
2. 查看secrete,进入容器:docker exec -it demo sh
eg: cat /run/secrets/my-pw
3. mysql service 创建的时候指定secret文件
eg: docker service create --name db --secret my-pw -e MYSQL_ROOT_PASSWORD_FILE=/run/secrets/my-pw mysql:5.7
4. compose 中使用secret:
version: '3.7'
services:
web:
image: wordpress
ports:
- 8080:80
secrets:
- my-pw
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_PASSWORD_FILE: /run/secrets/my-pw
networks:
- my-network
depends_on:
- mysql
deploy:
mode: replicated
replicas: 3
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
update_config:
parallelism: 1
delay: 10s
mysql:
image: mysql:5.7
secrets:
- my-pw
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/my-pw
MYSQL_DATABASE: wordpress
volumes:
- mysql-data:/var/lib/mysql
networks:
- my-network
deploy:
mode: global
placement:
constraints:
- node.role == manager
volumes:
mysql-data:
networks:
my-network:
driver: overlay
# secrets:
# my-pw:
# file: ./password
secrets:
my-pw:
external: true
# name: my-pw2
更新service
1. 新建network: docker network create -d overlay demo
2. 创建service:docker service create --name web --publish 8080:5000 --network demo xiaopeng163/python-flask-demo:1.0
3. 增加web容器:docker service scale web=2
4. 更新image:docker service update --image xiaopeng163/python-flask-demo:2.0 web
5. 更新端口:ocker service update --publish-rm 8080:5000 --publish-add 8888:5000 web
7. compose.yml 更新, 需要更改yml文件,然后重新运行compose.yml文件,并且可以在yml中deploy字段设置更新模式
deploy:
mode: replicated
replicas: 3
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
update_config:
parallelism: 1 # 同时允许几个scale更新
delay: 10s # 每次更新延时
[外链图片转存失败(img-Hp3j3NNq-1563492635701)(https://i.imgur.com/jXubCbe.png)]
[外链图片转存失败(img-Nr4x9heR-1563492635701)(https://i.imgur.com/ZDVp2q7.png)]
八、Docker Cloud 之自动 build Docker image
[外链图片转存失败(img-bXZw861t-1563492635701)(https://i.imgur.com/ggw8nyD.png)]
[外链图片转存失败(img-WBNMqT8U-1563492635702)(https://i.imgur.com/CkSgUO6.png)]