原创 吴就业 143 0 2020-01-04
本文为博主原创文章,未经博主允许不得转载。
本文链接:https://wujiuye.com/article/ea389501b7684a40be1547c2b7f997e1
作者:吴就业
链接:https://wujiuye.com/article/ea389501b7684a40be1547c2b7f997e1
来源:吴就业的网络日记
本文为博主原创文章,未经博主允许不得转载。
本篇文章写于2020年01月04日,从公众号|掘金|CSDN手工同步过来(博客搬家),本篇为原创文章。
docker
容器化部署应用可以简化应用的部署流程。
假设部署一个应用需要在机器上安装和配置nginx
、tomcat
,如果需要新增一台服务器,或者切换服务器,那么就要重复同样的操作,安装nginx
、tomcat
并配置。容器化部署就是一次配置到处使用,将安装nginx
配置nginx
这一系列工作制作成一个镜像,在服务器上通过docker
拉取镜像并启动容器即可,基于此实现集群自动伸缩。
docker
入门简单,用好难,特别是制作镜像。随便做一个镜像就是1g
大小,这该怎么用。如果每次部署都要拉1g
的镜像,那么部署就要等待非常长的时间。如果在Dockerfile
中使用yum
安装一些软件,build
的时间会很长,加上镜像太大,传输也耗时。应尽量使用安装包安装替换yum
安装,以及使用尽量小的基础镜像。
使用Dockerfile
构建镜像,我们可以理解为,docker
基于Dockerfile
中的FROM
基础镜像,启动了一个容器,然后在容器中执行Dockerfile
中定义的脚本,执行完成后再打包成镜像。
docker
的镜像是分层的,你可以先定制一个基础镜像,再通过基础镜像去实现差异化定制。
比如部署一个java
项目,每台机器都需要jdk
,但并不是每台机器都需要安装nginx
,那么就可以先制作一个jdk
基础镜像。当然,制作jdk
基础镜像也是基于更底层的基础镜像,比如centos
。然后再基于jdk基础镜像制作nginx镜像,再制作应用镜像。制作应用镜像如果需要用到nginx
就可以基于nginx
镜像,不需要依赖nginx
的就可以直接基于jdk
镜像。
docker
的命令不需要记,动动手去试一试就记住了,记不住可以使用docker -help
查看命令。新版本docker
将命令规范了,如docker image
是镜像相关的,docker container
是容器相关的,同样,也可以使用docker container -help
来查看命令帮助。
学习doker
除了镜像制作之外,还需要理解这三点:端口映射、网络模式、容器卷(volume
)。
将宿主机端口映射到容器的端口,外部通过访问宿主机端口从而访问容器内应用。
如容器中redis使用的端口是6379
,可以将宿主机的10880
端口与容器的6379
端口映射,外部通过宿主机ip
和10880
端口访问容器中的redis
。
### 使用镜像运行容器
### -p 10880:6379 将宿主机10880端口映射到容器6379端口
[root@wujiuye01 redis-app]# docker container run -itd --name simple-redis \
-p 10880:6379 wujiuye/simple-redis:5.0.7
05676da445839b1f4a1995148b4656d029721503a16d67edad37956fe7ea9f3a
### 宿主机访问容器中的redis
[root@wujiuye01 redis-app]# /root/redis/redis-5.0.5/src/redis-cli -p 10880
127.0.0.1:10880>
docker
支持5
种网络模式,这里不做详细分析。
在启动容器时,可以指定使用哪种网络模式:docker container run --network [网络模式]
。
bridge
: 默认使用,docket
启动后默认创建一个docker0
网桥,默认创建的容器也是添加到这个网桥中。host
: 容器不会获得一个独立的network namespace
,而是与宿主机共用一个。应用部署在一台服务器上运行会产生日记,不能随着容器的删除而导致日记被删除,所以需要将容器中的工作目录与宿主机的目录映射。或者说mysql
容器,容器移除而数据库文件不能删除。
docker
为我们提供了三种不同的方式将容器卷或宿主机目录从宿主机挂载到容器中:volume
、bind mount
、tmpfs
。
docker
管理宿主文件系统的一部分(/var/lib/docker/volumes/容器id
)
docker volume create test-vol
docker volume inspect test-vol
docker container run -itd --name test --mount src=test-vol,dst=/data/apps/test wujiuye/test:1.0.0
docker container run
命令指定的--mount src=test-vol,dst=/data/apps/test
是将容器卷挂载到容器的/data/apps/test
目录。将文件放到容器的/data/apps/test
目录下,可以在宿主机的/var/lib/docker/volumes/test-vol
目录看到,反过来也是一样的。如果不指定--mount
,默认也是使用volumes
,并且容器卷的名称就是容器id
,也是在 /var/lib/docker/volume/
目录下。
### 创建容器卷
[root@wujiuye01 docker]# docker volume create test-vol
test-vol
### 查看容器卷信息
[root@wujiuye01 docker]# docker volume inspect test-vol
[
{
"CreatedAt": "2020-01-04T17:57:08+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/test-vol/_data",
"Name": "test-vol",
"Options": {},
"Scope": "local"
}
]
### 将容器卷挂载到容器
[root@wujiuye01 docker]# docker container run -itd --name test \
--mount src=test-vol,dst=/data/apps/test wujiuye/test:1.0.0
可以存储在宿主机系统的任意目录,宿主机的目录必须存在。
如果宿主机新增磁盘是挂载在/data
目录的,建议使用这种,如使用aws
的ec2
实例。
docker container run -itd --name test \
--mount type=bind,src=宿主机目录,dst=容器目录 wujiuye/test:1.0.0
将指定的宿主机目录挂载到容器的指定目录:将文件放到<容器指定目录>
下,可以在<宿主机指定目录>
看到,反过来也是一样的。
挂载存储在宿主机系统的内存中,不会写入宿主机的文件系统。
docker安装
# 较旧的 Docker 版本称为 docker 或 docker-engine 。如果已安装这些程序,请卸载它们以及相关的依赖项。
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
# 安装所需的软件包。yum-utils 提供了 yum-config-manager ,并且 device mapper 存储驱动程序需要 device-mapper-persistent-data 和 lvm2
sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
# 设置稳定的仓库。
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
# 安装最新版本的 Docker Engine-Community 和 containerd
sudo yum install docker-ce docker-ce-cli containerd.io
docker服务启动与停止
## 停止
sudo systemctl stop docker
## 启动
sudo systemctl start docker
准备redis
安装包和配置文件,新建一个Dockerfile
文件,目录结构如下:
-rw-r--r-- 1 root root 583 Jan 4 18:56 Dockerfile
-rw-r--r-- 1 root root 1984203 Jan 4 18:52 redis-5.0.7.tar.gz
-rw-r--r-- 1 root root 61797 Jan 4 18:52 redis.conf
编写Dockerfile
文件,基于centos:7
镜像:
FROM centos:7
MAINTAINER wujiuye <[email protected]>
# 使用ps 命令 :ps -ef|grep redis
RUN yum install -y procps
# redis安装包和配置文件
ADD redis-5.0.7.tar.gz /usr/local/redis/
COPY redis.conf /usr/local/redis/local-redis.conf
# 安装gcc
RUN yum install gcc -y
# 安装make
RUN yum install make -y
# 编译redis
RUN cd /usr/local/redis/redis-5.0.7 && \
make
RUN yum clean all
EXPOSE 6379
# 启动redis
ENTRYPOINT /usr/local/redis/redis-5.0.7/src/redis-server
CMD ["/usr/local/redis/local-redis.conf"]
COPY
、ADD
命令的src
只能使用相对路径,需要将文件拷贝到Dockerfile
的同级目录下redis
安装包与redis
配置文件COPY
或ADD
到容器的挂载目录下,否则因宿主机的源目录下没有这些文件,容器启动起来就找不到这些文件。构建镜像时将文件放在容器的/data/apps/
目录下,而启动容器时配置宿主机目录挂载到容器的/data/apps/
,docker
会将镜像中原有的/data/apps/
目录移除,才可以挂载。RUM
运行多条命令可使用&&
符号连接,也可以写多个RUN
### 目录下的文件
[root@wujiuye01 redis-app]# ls
Dockerfile redis-5.0.7.tar.gz redis.conf
### 构建镜像
[root@wujiuye01 redis-app]# docker image build --tag wujiuye/simple-redis:5.0.7 .
....
Successfully built 2aab79854763
Successfully tagged wujiuye/simple-redis:5.0.7
--tag
打标签,最后的‘.’
是Dockerfile
文件所在的位置。
docker container run \
--rm -itd \
--ulimit nofile=102400:102400 \
--name=simple-redis \
-p 10880:6379 \ # 可写多个
--mount type=bind,src=/data/redis-app/,dst=/usr/local/redis \
wujiuye/simple-redis:5.0.7
--rm
: 如果容器存在则删除,只是移除容器,正在运行的容器不会停止--name=simple-redis
: 给容器取一个名字-itd
: -i
、-t
、-d
的结合--ulimit nofile=102400:102400
设置ulimit
-p 10880:6379
宿主机与容器的端口映射--mount type=bind,src=...,dst=...
文件系统为bind mount
,src
为宿主机的目录,dst
为容器中的目录使用docker container ls
命令列出所有容器。
[root@wujiuye01 redis-app]# docker container ls
### 容器id 使用的镜像 容器执行的命令 创建时间 容器状态 端口信息 容器名称
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
05676da44583 wujiuye/simple-redis:5.0.7 "/bin/sh -c /usr/loc…" 6 minutes ago Up 6 minutes 0.0.0.0:10880->6379/tcp simple-redis
在测试完镜像可用之后,可以选择push到远程仓库,也可自己搭建一个镜像仓库。
hub.docker.com
账号,id
不要随便填写,如:wujiuye
wujiuye/simple-redis
docker tag local/test-redis:1.0.5 wujiuye/simple-redis:5.0.7
。本地镜像与远程仓库镜像标签不同时使用。docker login
输入用户名密码登陆docker push wujiuye/simple-redis:5.0.7
推送镜像至远程仓库[root@wujiuye01 redis-app]# docker push wujiuye/simple-redis:5.0.7
The push refers to repository [docker.io/wujiuye/simple-redis]
dafbadcc43aa: Pushing [==> ] 1.281MB/23.62MB
879a0e8874ba: Pushing [=============================> ] 66.96MB/111.8MB
ccc522a455bc: Pushing [> ] 549.9kB/100.2MB
879a0e8874ba: Pushing [================================> ] 73.04MB/111.8MB
ccc522a455bc: Pushing [> ] 1.107MB/100.2MB
ff7b8add839d: Pushing [=================> ] 51.75MB/146.8MB
dca066a10cae: Pushing [> ] 557.1kB/100.8MB
77b174a6a187: Waiting
容器停止
1)、docker kill [容器名]
可选参数:
--signal: 发送信号量
2)、docker stop []
删除容器和镜像
docker rmi $(docker images -q)
1)、先停止所有容器:docker stop $(docker ps -a -q)
2)、删除所有容器:docker rm $(docker ps -a -q)
删除某个镜像:
1)、docker image rm [repository,如:wujiuye/simple-redis:5.0.7]
2)、docker image rm [镜像id]
删除某个容器:
docker container rm [容器名称 或 容器id]
声明:公众号、CSDN、掘金的曾用名:“Java艺术”,因此您可能看到一些早期的文章的图片有“Java艺术”的水印。
我看很多资料在介绍`GC Root`时,并没有说栈帧的操作数栈上引用的对象也是`GC Root`,包括我去翻阅《深入理解Java虚拟机》这本书也是一样。所以我才好奇。
线上某服务一直运行很稳定,最近突然就`cpu`百分百,`rpc`远程调用全部失败,并走了`mock`逻辑。重启后,一个小时后问题又重现。于是`dump`线程栈信息,但不仔细看也看不出什么问题。于是就有了一番排查历程。
最近看书看到关于`volitale`关键字与`jmm`内存模型的介绍,这个知识点似乎看了好多次,背都能背下来了。但理论性的东西真的很容易忘记,看不到摸不着。于是乎,我上网搜索看底层机器指令的实现,发现不少文章说可以看到`java`编译后的汇编代码,于是了解到`jitwatch`这个工具,从名字上也能看出`jit`编译器监视的意思。
Dubbo框架的传输层默认使用dubbo协议,这也是一种RPC远程通信协议。学习Dubbo,我们有必要了解dubbo协议长什么样,最好的办法就是从源码中寻找答案。
今天我们来分析下`netty`是如何解析`http`协议数据包的。重点是分析`HttpObjectDecoder`类的`decode`方法的源码,`http`协议数据包的解码操作都是在该方法中完成的。
订阅
订阅新文章发布通知吧,不错过精彩内容!
输入邮箱,提交后我们会给您发送一封邮件,您需点击邮件中的链接完成订阅设置。