Docker
底层技术支持
- Namespaces:做隔离pid,net,ipc,mnt,uts(这是都是linux底层)
- Control groups:做资源限制
- Union file systems:Container和image的分层
docker学习网站
https://yeasy.gitbooks.io/docker_practice/install/mirror.html
docker安装
# 检查内核版本,必须是3.10及以上
uname -r
# 安装docker
yum install docker* -y
# 查看docker软件是否安装
rpm -qa | grep docker
# 启动docker
systemctl start docker
# 开机启动
systemctl enable docker
docker命令
docker基本命令
# 搜索镜像
docker search tomcat
# 拉取镜像
docker pull tomcat
docker pull 镜像名:tag
# 加速registry.docker-cn.com/library/,后面跟上相对应的版本,去docker仓库里查看
docker pull registry.docker-cn.com/library/rabbitmq:3.7-management
3、根据镜像启动容器,mytomcat自己取名字 -d:后台运行,image-name:指定镜像模板
docker run --name mytomcat -d tomcat:latest
4、docker ps
查看运行中的容器
5、 停止运行中的容器
docker stop 容器的id
6、查看所有的容器
docker ps -a
7、启动容器
docker start 容器id
8、删除一个容器
docker rm 容器id
docker rm -f 容器id # 可以删除正在运行的容器
9、启动一个做了端口映射的tomcat
docker run -d -p 8888:8080 tomcat
-d:后台运行
-p: 将主机的端口映射到容器的一个端口 主机端口:容器内部的端口
-it:交互式运行
# 删除镜像
docker rmi image/id
docker命令
-i interactive 交互
-t tty 终端
-d daemon 后台运行
# 交互式运行
docker run -it centos
# 显示所有的容器
docer ps -aq
docker container ls -aq
docker container ls -a | awk {'print$1'}
# 删掉所有容器
docker rm $( docker container ls -aq )
docker rm -f flask # 强制删除正在运行的容器
# 把状态为exited的容器查询出来
docker container ls -f "status=exited"
docker ps -f "status=exited" | awk {'print$1'}
# 删除状态为exited的容器,没有启动的容器
docker rm $( docker ps -f "status=exited" | awk {'print$1'} )
# 查看容器的ip
docker exec -it 容器id ip a
docker inspect 容器id | grep -i ipaddress
# 把主机的文件拷贝到容器
docker cp /Users/liheng/Desktop/iqiyi.zip 7ed9c6fbf986:/
进入运行环境
# 不用进入bash环境执行命令
docker exec 容器id 命令
# 进入bash环境
docker exec -it 容器id /bin/bash # 执行命令,进入交互式环境
# 进入python环境
docker exec -it 容器id python
# 查看该容器的ip
docker exec -it 容器id ip a
# 查看容器的详细信息
docker inspect 容器id
# 查看容器的log
docker logs 容器id
docker 保存和加载
# 保存
docker save -o fedora-latest.tar fedora:latest
docer save 容器id > xxx.tar
# 加载
docker load < busybox.tar.gz
docker load --input fedora.tar
docker load -i fedora.tar
# 给镜像添加名称和标签
docker tag id号 zbyft/centos-vim:latest
# commit,生成镜像
docker commit id zbyft/centos-vim
docker 知识点
一台宿主机上的docker容器是相互通信
# 启动centos容器,--privileged:以超级权限启动,
docker run --privileged -itd -p 80:80 -p 6022:22 --name centos6 centos6
创建简单镜像
# 使用commit
# 拷贝镜像lucid_stonebraker,是容器停止后的names,docker ps -a
docker commit lucid_stonebraker zby/centos-vim
# 使用Dockerfile来创建(推荐)
# 在/tmp/docker_builder/下创建Dockerfile
# Dockerfile
FROM centos:latest # 依赖的镜像,初始镜像
RUN yum install -y vim
# 执行命令
docker build -t zby/centos-vim /tmp/docker_builder/
# 生成自己的镜像
# Dockerfile
FROM python:3.7
CMD ["python","/data/www/hello.py"]
# 生成镜像,my-python-app生成的镜像名,指定Dockerfile的目录/tmp/docker_builder/
docker build -t my-python-app /tmp/docker_builder/
Dockerfile语法
FROM
FROM scratch # 只做base image,不依赖任何镜像
FROM centos # 使用base image
FROM ubuntu:14.04
LABLE 标签
LABEL maintainer="zby@qq.com"
LABEL version="1.0"
LABEL description="This is description"
RUN
RUN yum update && yum install -y vim \
python-dev # 反斜线换行
# 为了美观,复杂的RUN请用反斜线换行,避免无用分层,合并多条命令成一行
WORKDIR
# 类似如cd操作
WORKDIR /test # 如果没有会自动创建test目录
WORKDIR demo
RUN pwd # 输出结果应该是 /test/demo
# 用WORKDIR,不要用RUN cd,尽量使用绝对目录
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
RUN wget ...
ENV
# 定义变量
ENV MYSQL_VERSION 5.6 # 设置常量
RUN apt-get install -y mysql-server= "${MYSQL_VERSION}" \
&& rm -rf /var/lib/apt/lists/* # 引用常量
# 尽量使用ENV增加可维护性
VOLUME and EXPOSE
# 存储和网络
EXPOSE 5000 # 暴露端口
CMD and ENTRYPOINT
RUN:执行命令并创建新的Image Layer
CMD:设置容器启动后默认执行的命令和参数
ENTRYPOINT:设置容器启动时运行的命令
# Shell格式
RUN apt-get install -y vim
CMD echo "hello docker"
ENTRYPOINT echo "hello docker"
# Exec格式
RUN ["apt-get", "install", "-y", "vim"]
CMD ["echo","hello docker"]
ENTRYPOINT ["echo","hello docker"]
# Dockerfile1
FROM centos
ENV name Docker
ENTRYPOINT echo "hello $name"
# Dockerfile2
FROM centos
ENV name Docker
# ENTRYPOINT ["echo","hello $name"] # 此时打印不出来hello Docker
ENTRYPOINT ["bash", "-c", "echo hello $name"]
# CMD
容器启动时默认执行的命令
如果docker run指定了其它命令,CMD命令被忽略
如果定义了多个CMD,只有最后一个会执行
# ENTRYPOINT
让容器以应用程序或者服务的形式运行
不会被忽略,一定会执行
最佳时间:写一个shell脚本作为entrypoint
COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 27017
CMD ["mongod"]
镜像的发布
镜像发布
# 登录
docker login
# push镜像,注意命令规范,前面必须是自己的docker ID
docker push zbyft/hello-world:latest
创建私有docker hub
# 在一台服务器上启动私有仓库,ip为192.168.220.130
docker run -d -p 5000:5000 --restart always --name registry registry:2
# 在另一台服务器,192.168.43.7
# 创建镜像,命令规范
docker build -t 192.168.220.130:5000/hello-docker:latest .
# 在/etc/docker/daemon.json下添加以下内容
{
"insecure-registries":["192.168.220.130:5000"]
}
# 在修改docker的启动文件,/lib/systemd/system/docker.service
vim /lib/systemd/system/docker.service
# 添加
EnvironmentFile=/etc/docker/daemon.json
# 重启docker
sudo systemctl daemon-reload
sudo systemctl restart docker
# 此时就可以push了
docker push 192.168.220.130:5000/hello-docker:latest
# 注意
ping一下这祥两台服务器是否ping的通
部署flask应用
app.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello():
return "hello docker"
if __name__== "__main__":
app.run(host="0.0.0.0")
Dockerfile
FROM python:3.7
LABEL maintainer="zby@qq.com"
RUN pip install flask
COPY ./app.py /app/
WORKDIR /app/
EXPOSE 5000 # 暴露端口
CMD ["python","app.py"]
调试Dockerfile
# 进入Dockerfile里的容器里
docker run -it 容器id /bin/bash # 交互式
使用stress工具
Dockerfile
FROM ubuntu
RUN apt-get update && apt-get install -y stress
ENTRYPOINT ["/usr/bin/stress"]
CMD [] # []作用是用接收参数
# 制作镜像
docker build -t zbyft/ubuntu-stress .
执行stress镜像
docker run -it 40f52d6db972 --vm 1 --verbose
部署带redis的项目
构建flask-redis项目
# 先启动redis的镜像
docker run -d --name redis redis
# Dockerfile
FROM python:3.7
LABEL maintainer="zby@qq.com"
RUN pip install flask redis
COPY ./app.py /app/
WORKDIR /app/
EXPOSE 5000
CMD ["python", "app.py"]
# 构建镜像
docker build -t zbyft/flask-redis .
# -e 给该容器设置环境变量
# 启动,--link,镜像redis的名字,表示可以通过名字就可以连接redis镜像,设置环境变量REDIS_HOST=redis
docker run -d --name flask-redis -p 5000:5000 --link redis -e REDIS_HOST=redis zbyft/flask-redis
app.py
# -*- coding: utf-8 -*-
from flask import Flask
import redis
import os
app = Flask(__name__)
redis_conn = redis.Redis(host=os.environ.get("REDIS_HOST", "127.0.0.1"), port=6379)
@app.route("/")
def index():
redis_conn.incr("num")
return "hello redis: %s" % redis_conn.get("num")
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000, debug=True)
数据持久化
Data Volume
# 查看数据volume
docker volume ls
# 删除数据卷
docker volume rm 名字
# 在Dockerfile里添加,数据存储的路径,表示容器存储的数据在容器该路径下
VOLUME ["/var/lib/mysql"]
# 在启动容器时添加参数,volume的名字:容器的位置,数据库的密码为my-secret-pw
docker run --name mysql1 -v mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:5.7
# 进入该容器
docker exec -it mysql1 /bin/sh
mysql -uroot -pmy-secret-pw
# 创建数据库docker
create databases docker;
# 停止容器
# 在启动一个新的容器,用该volume(mysql)
docker run --name mysql2 -v mysql:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:5.7
# 该数据库里有原来的数据,即有数据库docker
Bind Mouting
# 本机的数据位置:容器里的数据位置
docker run -v /home/aaa:/root/aaa
# 启动,当前的目录和容器的目录/usr/share/nginx/html,共享
docker run -d -p 80:80 --name nginx -v $(pwd):/usr/share/nginx/html zbyft/nginx-index
network
- docker network create -d bridge my-bridge
安装wordpress
启动mysql容器
docker search mysql
# 下载5.7版本的mysql
docker pull docker.io/centos/mysql-57-centos7
docker run -d --name mysql -v /data/mysql:/usr/lib/mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw docker.io/centos/mysql-57-centos7
# 进入mysql容器中
docker exec -it mysql /bin/sh
mysql -uroot -p # 不需要输入密码,直接回车进入
create database wordpress charset=utf8;
启动wordpress
# 下载wordpress
docker pull wordpress
docker run -d --name wordpress -e WORDPRESS_DB_HOST=mysql:3306 --link mysql -p 8080:80 wordpress
# 直接访问
ip:8080
docker compose
docker-compose.yml
# 三大概念
Services Networks Volumes
Services
- 一个service代表一个container,这个container可以从dockerhub的image来创建,或者从本地的Dockerfile build出来的image来创建
- Service的启动类似docker run,我们可以给其指定network和volume,所以可以给service指定network和Volume的引用
例如:
services:
db:
image: postgres:9.4
volumes:
- "db-data:/var/lib/postgresql/data"
networks:
- back-tier
# 就相当于
docker run -d --network back-tier -v db-data:/var/lib/postgresql/data postgres:9.4
完整的实例:
version: '3'
# docker run
services:
# service的改名字,也可以理解成该容器的名字 --name,最后生成的名字确不是这个名字,但一样可以使用改名字,在docker-compose
wordpress:
image: wordpress
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_PASSWORD: root
networks:
- my-bridge
# 可以理解成名字 --name
mysql:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: wordpress
volumes:
- mysql-data:/var/lib/mysql
networks:
- my-bridge
# docker volume create mysql-data
volumes:
mysql-data:
# docker network create -d bridge my-bridge
networks:
my-bridge:
driver: bridge
安装
sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$( uname -s )-$( uname -m )" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
# 如果下载不下来,就使用pip来装
https://blog.csdn.net/jojoy_tester/article/details/79182216
使用
docker-compose up # 会自动从当前的路径找docker-compose.yml文件
docker-compose -f docker-compose.yml up # 指定要启动的yml文件
# 后台启动
docker-compose up -d
# 停止
docker-compose stop
# 开始
docker-compose start
# 删除并重启
docker-compose down
# 进入到容器里exec
docker-compose exec mysql bash # 进入到mysql的容器里
flask和redis的使用
Dockerfile
FROM python:3.7
LABEL maintainer="zby@qq.com"
RUN pip install flask redis
COPY ./app.py /app/
WORKDIR /app/
EXPOSE 5000
CMD ["python", "app.py"]
app.py
# -*- coding: utf-8 -*-
from flask import Flask
import redis
import os
app = Flask(__name__)
redis_conn = redis.Redis(host=os.environ.get("REDIS_HOST", "127.0.0.1"), port=6379)
@app.route("/")
def index():
redis_conn.incr("num")
return "hello redis: %s" % redis_conn.get("num")
if __name__ == '__main__':
app.run(host="0.0.0.0", port=5000, debug=True)
docker-compose.yml
version: "3"
services:
redis:
image: redis
web:
build:
context: . # 指定Dockerfile的位置
dockerfile: Dockerfile # 指定文件名
ports:
- 8080:5000
environment:
REDIS_HOST: redis
水平扩展和负载均衡
- 启动多个web应用服务
docker-compose.yml
version: "3"
services:
redis:
image: redis
web:
build:
context: . # 指定Dockerfile的位置
dockerfile: Dockerfile # 指定文件名
environment:
REDIS_HOST: redis
lb: # 相当于是中间人,首先都访问它,然后由它分发到各个web服务上面
image: dockercloud/haproxy
links:
- web
ports:
- 8080:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock
启动服务
docker-compose up -d
# 开启多个web服务,外界访问的话,会轮询各个服务器达到负载均衡
docker-compose up --scale web=3 -d # scale:规模
# 访问
http://192.168.43.7:8080/
app.py
# 修改一点
if __name__ == '__main__':
app.run(host="0.0.0.0", port=80, debug=True)
制作centos镜像
https://blog.csdn.net/liudian_cz/article/details/88850773
# 启动制作的镜像
docker run --privileged -d -it --name centos centos /usr/sbin/init
docker run --privileged -d -it -p 7000:6379 -p 4000:3306 --name centos 1316abe84234 /usr/sbin/init