Docker
简介
- 开源的应用容器引擎,基于Go语言
- 完全隔离的沙箱机制,类似app之间的关系
重要的是性能开销极低
- 程序简化
- docker镜像中包含环境,服务环境搭建简单
应用场景
- web自动打包发布
- 自动化测试
- 在服务型环境中部署,调整 应用
Docker引擎
Docker系统架构
- 使用客户端-服务器架构模式,使用远程api来管理和创建Docker容器
- Docker容器通过Docker镜像来创建
关系:容器---》对象,镜像------》类
- 镜像封装了基本的属性
- 真正操作的是容器,
docker pull ---->守护进程---》创建两个容器------》本机存在镜像的时候直接创建,否则到docker库下载
Docker安装
- 可以安装在windwos,mac,linux
前提条件
- 若为linux只适用于64位
- linux内核要大于3.10
- https://www.dean0731.cn/archives/582/
第一个Docker应用程序
# 从网上下载ubuntu15.10 的镜像,创建一个容器 ,使用容器打印 “hello docker"
docker run ubuntu:15.10 /bin/echo "hello Docker"
docker images
docker ps
docker rm containerID
# 用主线程的交互式容器,即可进入Ubuntu容器 root命令行
docker run -it ubuntu:15.10 /bin/bash
后台运行 -d表示在后台
docker run -d ubuntu:15.10 /bin/bash -c "while true:do echo hello docker;sleep 1;done"
# 查看容器日志,加参数 -f可动态查看
docker logs containerId
docker stop containerId
# 适用bash与正在运行的容器进行交互
docker exec -it containerId /bin/bash
docker COMMAND --help
运行web容器
# 在一个完整的操作系统上运行python程序
# -P:表示把容器的端口映射到宿主机,宿主机随机一个端口映射到容器
# 镜像为training/webapp
# 它是一个flask程序 运行命令python app.py
docker run -d -P training/webapp python app.py
# 可以指定访问端口 宿主机4000,容器5000
docker run -d -p 4000:5000 training/webapp python app.py
# 查看容器中的进程
docker top containerId
docker top names
# 查看容器状态:json字符格式
docker inspect
# 出现一个新的image,与上个同名,tag不同, 设置镜像标签
docker tag containerId imageName:newTag
docker 安装后会产生一个虚拟网卡,mac等,容器产生的Ip都是基于虚拟网卡的
Docker镜像管理
若使用的镜像不存在会从 Docker Hub 下载
docker pull tomcat
docker pull tomcat:8.5.49-jdk11-openjdkv
# 镜像,默认获取最新版本,也可以指定版本获取
# 镜像,一般选择官方的,使用docker pull name 获取
# starts 表示的是使用量,可作为评价标准
docker search tomcat
# 创建镜像from容器
docker commit -m="has update" -a="userName" containerId newImageName:Tag(随便)
# Dockerfile创建镜像
mkdir myUbuntu
cd myUbuntu
vi Dockerfile #(名字不要更改)
FROM ubuntu:15.10 # 系统
MAINTAINER your-email
COPY test.txt /home # 将宿主机的文件test.txt copy 到镜像的home下
RUN /bin/bash -c "Hello world" # 指定镜像默认执行的命令
CMD ["/bin/echo","this is param1"] # 文件中只能有一个cmd,有多个会只执行第一个
WORKDIR /home # 指定默认的工作目录
EXPOSE 80 # 暴露端口
EXPOSE 8080
docker build -t yourImageName . # 在当前目录查找dockerfile 为改文件的镜像命名
Docker实例教程
# 使用docker 后台运行tomcat容器 并做端口映射,并修改容器的默认名字为tomcat,
docker run --name tomcat -p 8080:8080 -d tomcat
# 若要在容器内tomcat 部署程序,交互式进入,写自己的html即可
docker pull mysql # 拉去mysql 镜像
docker run -p 3306:3306 -name mysql \
-v /usr/local/deoker/mysql/conf:/etc/mysql \ # 映射宿主机目录到容器目录
-v /usr/local/docker/mysql/logs:/val/log/mysql \ # -v 数据卷
-v /usr/local/docker/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \ # -e 指定环境边变量
-d mysql
# 若以后要重新运行时,密码变更了,需要删除宿主机下原来的数据卷,否则会不生效,还使用原来的配置。
vim Dockerfile
FROM tomcat
MAINTAINER email
ADD xxx.war /usr/local/tomcat/webapps/xxx.war # 添加war包到容器
docker build -t name . # 构建镜像
docker run -d -p 8080:8080 imageName
# 本方式是直接将war打入本镜像,比较麻烦,可使用数据卷解决
数据卷
- 绕过拷贝写,修改容器内容相当于直接修改宿主机内容,性能高
- 不需要在docker commit 打包进镜像文件
- 宿主,容器,容器之间共享文件
- 创建数据卷
docker run -d -P -v /webapps training/webapps python app.py
# 将tomcat容器的目录映射到宿主目录,即时原容器目录有内容也不可用
docker run -name tomcat1 -d -p 8080:8080 -v /usr/local/docker/tomcat/share/webapps:/usr/local/tomcat/webapps tomcat
# 或
dockerfile中指定 VOLUME /var/lib/test
- 备份数据卷
docker run -p 3306:3306 -name mysql \
-v /usr/local/deoker/mysql/conf:/etc/mysql \
-v /usr/local/docker/mysql/logs:/val/log/mysql \
-v /usr/local/docker/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-d mysql
# 启动数据库
# 1. 连接容器内数据库,做出修改
# 2. 进入宿主机的数据卷,直接备份docker/mysql目录即可 tar -zcvf backup.tar.gz .
# 3. 恢复数据卷,其重新的容器时,挂载备份的文件即可
Docker Compose
- 简化docker操作的工具,安装docker-compose
curl -L https://github.com/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
# 或直接下载上传即可,重命名为docker-compose,放入环境变量目录
chown -R root:root docker-compose
chmod +x docker-compose
# 官网那个可能慢
curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.5/docker-compose-`uname -s`-`uname -m`>/usr/local/docker-compose
- docker-compose 使用
# 启用tomca容器
# 原始方法:docker run .......
# docker-compose
mkdir tomcat;cd tomcat
vim docker-compose.yml # yml 语言
version: "3" # compose的版本号决定
services:
tomcat: # 服务名字,可变的
restart:always
image:tomcat
container_name:tomcat
ports:
- "8080:8080"
docker-compose up # 此时是主线程启动
docker-compose down # 停止,并删除
docker-compose up -d # 后台运行 必须在docker-compose.yml所在的目录
version: "3"
services:
tomcat:
restart:always
image:tomcat
container_name:tomcat
ports:
- "8080:8080"
volumes:
- "/usr/local/docker/tomcat/webapps/test:/usr/local/tomcat/webapps/test"
environment:
TZ: Asia/Shanghai
# mysql
version: "3"
services:
mysql:
restart: always
image:mysql
container_name:mysql
port:
- 3306:3306
environment:
TZ:Asia/Shanghai
MYSQL_ROOT_PASSWORD:123456
command:
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_name=1
--max_allowed_packet=128M
--sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBST\
ITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATA,ERROR_FOR_DIVISION_BY_ZERO"
volumes:
- mysql-data:/var/lib/mysql
volumes:
mysql-data: # docker安装目录/volumes/下创建mysql_mysql-data文件夹作为映射
# /var/lib/docker/volumes/mysql_mysql-data
version: 3
services:
tomcat:
restart:always
image:tomcat
container_name:tomcat
ports:
- 8080:8080
volumes:
- /usr/local/docker/project/webapps/:/usr/local/tomcat/webapps/
environment:
TZ: Asia/Shanghai
mysql:
restart: always
image:mysql
container_name:mysql
port:
- "3306:3306"
environment:
TZ:Asia/Shanghai
MYSQL_ROOT_PASSWORD:123456
command:
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_name=1
--max_allowed_packet=128M
--sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SU\
BSTITUTION,NO_ZERO_DATE,NO_ZERO_IN_DATA,ERROR_FOR_DIVISION_BY_ZERO"
volumes:
- mysql-data:/var/lib/mysql
volumes:
mysql-data:
- 项目部署
# app.py
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)
# requirements.txt
flask
redis
# Dockerfile
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP app.py
ENV FLASK_RUN_HOST 0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]
# docker-compose.yml
version: '3'
services:
web:
build: . # 使用当前Dockerfile构建镜像
ports:
- "5000:5000"
redis:
image: "redis:alpine" # 使用现成镜像
# build
docker-compose build
# 启动
docker-compose up -d
- 创建网络
- 执行docker-compose.yml
- 启动服务
- 就是里面的镜像
- 默认服务名:文件名\_服务名\__num(运行实例个数)
- 网络
- docker network ls
- 通过compose启动,就会生成网络,因此项目中网络都是一个
- 访问时不用ip,使用服务名,更简洁,在springboot配置文件中 spring.redis.host=redis
version: "3.8"
services:
redis: # 服务
image: redis:alpine
ports:
- "6379"
networks:
- frontend
deploy:
replicas: 2
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
db: # 服务
image: postgres:9.4
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
deploy:
placement:
max_replicas_per_node: 1
constraints:
- "node.role==manager"
vote:
image: dockersamples/examplevotingapp_vote:before
ports:
- "5000:80"
networks:
- frontend
depends_on:
- redis
deploy:
replicas: 2
update_config:
parallelism: 2
restart_policy:
condition: on-failure
result:
image: dockersamples/examplevotingapp_result:before
ports:
- "5001:80"
networks:
- backend
depends_on:
- db
deploy:
replicas: 1
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
worker:
image: dockersamples/examplevotingapp_worker
networks:
- frontend
- backend
deploy:
mode: replicated
replicas: 1
labels: [APP=VOTING]
restart_policy:
condition: on-failure
delay: 10s
max_attempts: 3
window: 120s
placement:
constraints:
- "node.role==manager"
visualizer:
image: dockersamples/visualizer:stable
ports:
- "8080:8080"
stop_grace_period: 1m30s
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
placement:
constraints:
- "node.role==manager"
networks:
frontend:
backend:
volumes:
db-data:
# java dockerfile例子
FROM java:8
COPY *.jar /app.jar
CMD ["--server.port=8888"]
EXPOSE 8888
ENTRYPOINT ["java","-jar","/app.jar"]
version: '3.8'
services:
javaservice:
build: .
image: javaservice
depends_on:
- redis
ports:
- "8888:8888"
redis:
image: "redis:alpine"
集群 Docker Swarm
- 集群方式部署,主机更多的时候使用k8s
- xshell命令同步操作安装docker
- 工作模式
# swarm 集群初始化
docker swarm init --advertise-addr ip1 # 初始化节点 默认是lader,是管理节点
# 令牌生成
docker swarm join-token worker
docker swarm join-token manager
# 加入集群work。manager使用令牌加入
# worker,manager:Reachable,loader
# 一般情况管理节点大于等于3个,此时有损坏的开可以使用,若2管理节点,损坏一个后就不能使用了,即最少2个管理可使用,否则就会docker集群就不能使用了,raft协议:保证大多数节点存活
# docker node ls 查看节点
# docker swarm leave 离开集群
docker service,之前的集群,不能动态扩容,缩容
- 容器---》服务--》副本
# nginx 集群
# 服务启动 滚动更新,扩容,缩容,docker run不可以
# 会随机在worker启动
docker service -p 8888:80 --name my_nginx nginx
# 查看服务信息
docker service ps my_nginx
# 查看服务列表
docker service ls
# my_nginx 创建副本
docker service update --relipcas 3 my_nginx
# 作用同上
docker service scale my_nginx=3
# 访问时访问集群中任何一个都可以 https://ip1:8888,https://ip2:8888,即使ip2没有服务,但它在集群中
# 缩小
docker service update --relipcas 1 my_nginx
# 移除服务
docker service rm my_nginx
扩展:网络模式
overlay:集群中不同主机上的docker是不能ping的,此模式使用虚拟ip,完成此功能
imgress:overlay的进一步开发,有负载均衡作用
Docker stack
# 单机docker-compose
docker-compose up -d
# 集群docker stack
docker stack deploy
# 也是基于yaml文件,与compose格式类似
Docker secret
统一秘钥管理
Docker config
统一配置管理
扩展到k8s
- 云原生时代,直接云端下载应用,购买服务器,部署k8s即可使用
- go语言,天生的并发语言,docker,kvs,v8等都是go开发的
评论已关闭