docker

install:

 

sudo yum install -y yum-utils


sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

sudo yum install docker-ce docker-ce-cli containerd.io


sudo systemctl start docker

sudo systemctl enable docker

 sudo docker run hello-world

 

 

测试环境:

使用docker 启动mysql 做为测试环境:

拉取镜像:

docker pull mysql:latest
运行容器:
docker run -itd --name mysql-test -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql   (这里123456是root的密码)

sudo docker run -itd --name redis --restart  always --net=host redis  当指定--net=host 时 就不需要-p端口映射了

如果只端口映射,那么用外网ip+端口可以访问,但本地localhost是访问不了的。而使用host网络,本地localhost可以访问,


然后就可以在远程访问使用了:

mysql -u root -p -h 192.168.xx.xx(mysql 容器所在的机器)

 

指定volume,比如mysq存储的数据:

先建目录:sudo mkdir -p /opt/dockerVolumes/mysql-data-www2chat-merchant

然后添加-v参数:

sudo docker run -itd --name www2chat-merchant-mysql -p 3307:3306 -e MYSQL_ROOT_PASSWORD=123456 -v /opt/dockerVolumes/mysql-data-www2chat-merchant:/var/lib/mysql mysql

 

容器登陆MySQL,

docker exec -it mysql mysql -uroot -p

docker logs mysql 2>&1
查看docker日志

 

 

docker port  查看端口
docker inspect 查看容器配置
docker inspect --format='{{.NetworkSettings.IPAddress}}' container-name 查看容器ip
docker logs container-name 查看日志

---------------------------------------------------
Dockerfile, docker build

docker build [OPTIONS] PATH | URL | -
-f, --file string             Name of the Dockerfile (Default is 'PATH/Dockerfile')
 -t, --tag list                Name and optionally a tag in the 'name:tag' format

docker build -t nginx:v3 .
说白了就是用当前目录下的Dockerfile 制作标签为nginx:v3的镜像

注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。就是那个. 就是PATH

cat Dockerfile
FROM docker.elastic.co/logstash/logstash:8.1.3
RUN rm -f /usr/share/logstash/pipeline/logstash.conf
ADD pipeline/ /usr/share/logstash/pipeline/
ADD config/ /usr/share/logstash/config/

 

[root@1 dockerfile]# ls
config Dockerfile pipeline

 

[root@11 dockerfile]# ls config/
logstash.yml
[root@1 dockerfile]# ls pipeline/
kafka_to_es.conf

 

[root@1 dockerfile]# docker build -t logstash-8.1.3-kafka-to-es:v1 .
Sending build context to Docker daemon 19.46 kB
Step 1/4 : FROM docker.elastic.co/logstash/logstash:8.1.3
Trying to pull repository docker.elastic.co/logstash/logstash ...
8.1.3: Pulling from docker.elastic.co/logstash/logstash
0b785679cd71: Pull complete
14979cbdfceb: Pull complete

----------------------------------------------------------------------------------------
基础镜像:
scratch
alpine
centos
openjdk
python
mysql
mongo


我们通常会以一个镜像为基础,在其上进行定制,这就是基础镜像。

就像运行了一个 nginx 镜像的容器,再进行修改一样。在DockerFile中基础镜像是必须指定的 (FROM 就是指定 基础镜像,

因此一个 Dockerfile 中 FROM 是必备的指令,并且必须是第一条指令)

比如构建一个Java应用的镜像,选择一个Oracle JDK的镜像作为基础镜像比选择一个alpine镜像作为基础镜像更方便

都有哪些
在 Docker Hub 上有非常多的高质量的官方镜像,可以在其中寻找一个最符合我们最终目标的镜像为基础镜像进行定制。

应用镜像,如 nginx、redis、mongo、mysql、httpd、php、tomcat 等;

有方便开发、构建、运行各种语言应用的编程语言镜像,如 node、oraclejdk,openjdk、python、ruby、golang 等。

还有更为基础的操作系统镜像,如 ubuntu、debian、centos、fedora、alpine 等,这些操作系统的软件库为我们提供了更广阔的扩展空间。

除了选择现有镜像为基础镜像外,Docker 还存在一个特殊的镜像,名为 scratch。这个镜像是虚拟的概念,并不实际存在,它表示一个空白的镜像。

如果你在DockerFIle中以 scratch 为基础镜像的话(FROM scratch),意味着你不以任何镜像为基础,接下来所写的指令将作为镜像第一层开始存在。

不以任何系统为基础,直接将可执行文件复制进镜像的做法并不罕见,比如 swarm、coreos/etcd。对于 Linux 下静态编译的程序来说,

并不需要有操作系统提供运行时支持,所需的一切库都已经在可执行文件里了,因此直接 FROM scratch 会让镜像体积更加小巧。

使用 Go 语言 开发的应用很多会使用这种方式来制作镜像,这也是为什么有人认为 Go 是特别适合容器微服务架构的语言的原因之一。

 

如何选择Docker基础镜像
因为Docker镜像是基于基础镜像来构建的,因此选择的基础镜像越高级,我们要做的底层工作就越少。

比如,如果构建一个Java应用的镜像,选择一个openjdk的镜像作为基础镜像比选择一个alpine镜像作为基础镜像要简单地多。

镜像官网
Docker镜像官网(Docker Hub): https://hub.docker.com

阿里云容器Hub:https://dev.aliyun.com

Google镜像(gcr.io):https://console.cloud.google.com/gcr/images/google-containers/GLOBAL (需要,主要为Kubernetes相关镜像)

操作系统基础镜像
比如你要从Linux操作系统基础镜像开始构建,可以参考下表来选择合适的基础镜像:

镜像名称 大小 使用场景
busybox 1.15MB 临时测试用
alpine 4.41MB 主要用于测试,也可用于生产环境
centos 200MB 主要用于生产环境,支持CentOS/Red Hat,常用于追求稳定性的企业应用
ubuntu 81.1MB 主要用于生产环境,常用于人工智能计算和企业应用
debian 101MB 主要用于生产环境
busybox
描述:可以将busybox理解为一个超级简化版嵌入式Linux系统。

官网:https://www.busybox.net/

镜像:https://hub.docker.com/_/busybox/

包管理命令:apk, lbu

包管理文档:https://wiki.alpinelinux.org/wiki/Alpine_Linux_package_management

Alpine
描述:Alpine是一个面向安全的、轻量级的Linux系统,基于musl libc和busybox。

官网:https://www.alpinelinux.org/

镜像:https://hub.docker.com/_/alpine/

包管理命令:apk, lbu

包管理文档:https://wiki.alpinelinux.org/wiki/Alpine_Linux_package_management

CentOS
描述:可以理解CentOS是RedHat的社区版

官网:https://www.centos.org/

镜像:https://hub.docker.com/_/centos/

包管理命令:yum, rpm

Ubuntu
描述:另一个非常出色的Linux发行版

官网:http://www.ubuntu.com/

镜像:https://hub.docker.com/_/ubuntu/

包管理命令:apt-get, dpkg

Debian
描述:另一个非常出色的Linux发行版

官网:https://www.debian.org/

镜像:https://hub.docker.com/_/debian/

包管理命令:apt-get, dpkg

编程语言基础镜像
Java基础镜像
https://hub.docker.com/_/java/ (Deprecated)
https://hub.docker.com/_/openjdk/
由于Oracle JDK license问题,Docker官方的Java基础镜像使用的是OpenJDK而不是Oracle JDK。

Python基础镜像
https://hub.docker.com/_/python/
NodeJs基础镜像
https://hub.docker.com/_/node/
应用基础镜像
Nginx基础镜像
https://hub.docker.com/_/nginx/
Tomcat基础镜像
https://hub.docker.com/_/tomcat/
Jetty基础镜像
https://hub.docker.com/_/jetty/
其它基础镜像例子
Maven基础镜像
https://hub.docker.com/_/maven/
Jenkins基础镜像
https://hub.docker.com/r/jenkins/jenkins/
GitLab基础镜像
https://hub.docker.com/r/gitlab/gitlab-ce/

 

Dockerfile:

 

FROM golang:1.16.4 as builder

RUN go env -w GOPROXY=https://goproxy.cn
COPY . /go/src/app

# build app
# git describe --tags `git rev-list --tags --max-count=1` > VERSION && \
RUN cd /go/src/app && \
	date "+%Y-%d-%mT%TZ%z" > DATE && \
	echo "DATE:" $(cat DATE) && \
	git  branch | grep '*' | sed -e 's/\*//g' -e 's/HEAD detached at//g' -e 's/\s*//g' -e 's/[\(\)]//g'  > VERSION && \
	echo "VERSION:" $(cat VERSION) && \
	CGO_ENABLED=0 go build --ldflags "$LDFLAGS -s -w" -a -installsuffix cgo -v -o /app


FROM alpine:3.13.5

ARG UID=10000
ARG GID=10000
ARG ADDITIONAL_PACKAGE

RUN echo "https://mirror.tuna.tsinghua.edu.cn/alpine/v3.13/main" > /etc/apk/repositories && \
	addgroup -g $GID -S app && adduser -u $UID -S -g app app && \
	apk --no-cache add tzdata ${ADDITIONAL_PACKAGE}

COPY --from=builder /app /app/entry
WORKDIR /app
USER app
ENV TZ=Asia/Shanghai
EXPOSE 8080

CMD [ "/app/entry" ]

 

在第一部分中,我们需要一个完整的go环境来编译我们的软件。注意第一部分的名称和别名builder.编译完后,只有编译完得二进制程序是我们需要得,

在第二阶段使用 copy --from=builder 拿到

第二部分,只是把程序copy进去,在做一些设置而已。

 

简单版golang编译构建镜像得dockerfile:

FROM golang:1.7.3 AS builder
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]  

 

COPY 遵循的规则

<src> 路径必须在构建的上下文中

不能添加  ../something 、 /something ,因为 docker 构建的第一步是将上下文目录(和子目录)发送到 docker 守护进程

  • COPY 支持从其他构建阶段中复制源文件(--from)






---------------------------------------------------------------------------------

sh-5.0$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
elastic+ 1 0.0 0.0 2484 368 ? Ss 08:37 0:00 /bin/tini -- /usr/local/bin/docker-entrypoint.sh eswrapper
elastic+ 6 17.0 55.6 6864804 4456332 ? Sl+ 08:37 1:22 /usr/share/elasticsearch/jdk/bin/java -Xshare:auto -Des.networkaddress
elastic+ 297 0.0 0.0 108328 4152 ? Sl+ 08:38 0:00 /usr/share/elasticsearch/modules/x-pack-ml/platform/linux-x86_64/bin/c
elastic+ 359 0.1 0.0 4100 2060 ? Ss 08:45 0:00 /bin/sh
elastic+ 367 0.0 0.0 5884 1476 ? R+ 08:45 0:00 ps aux

pid等于1的进程是 entrypoint.sh 也就是 tini 可做进程管理

 

当你运行一个Docker容器时,镜像的ENTRYPOINT就是你的根进程,即PID 1(如果你没有ENTRYPOINT,那么CMD就会作为根进程,

你可能配置了一个shell脚本,或其他的可执行程序,容器的根进程具体是什么,完全取决于你的配置)。

与其他进程不同的是,PID 1有一个独特的职责,那就是收割“僵尸进程”。

那何为“僵尸进程”呢?

“僵尸进程”是指:

  • 已经退出。
  • 没有被其父进程wait(wait是指syscall父进程用于检索其子进程的退出代码)。
  • 父进程已丢失(也就是说,它们的父进程已经不存在了),这意味着他们永远不会被其父进程处理。

当“僵尸进程”被创建时(也就是说,一旦它的父进程非正常退出了,它也就跟着无法正常退出了),它会继承成为PID 1的子级,最后PID 1会负责关闭它。

换句话说,有人必须在“不负责任”的父进程离开后,对这些“孤儿”进行清理,这是PID 1的作用。

请注意,创建“僵尸进程”通常是不被允许的(也就是说,理想情况下,您应该修复代码,这样就不会创建“僵尸进程”),但是对于像Jenkins这种应用来说,它们是不可避免的:因为Jenkins通常运行的代码不是由Jenkins维护者编写的(也就是您的Jenkins构建脚本),所以他们也无法“修复代码”。

这就是Jenkins使用Tini的原因:在构建了创建“僵尸进程”的脚本后进行清理。

但其实Bash实际上也做同样的事情(收割“僵尸进程”),所以你可能会想:为什么不把Bash当作PID 1呢?

第一个问题是,如果您将Bash作为PID 1运行,那么您发送到Docker容器的所有信号(例如,使用docker stop或docker kill)最终都会发送到Bash,Bash默认不会将它们转发到任何地方(除非您自己编写代码实现)。换句话说,如果你使用Bash来运行Jenkins,那么当你运行docker stop的时候,Jenkins将永远收不到停止信号!

而Tini通过“信号转发”解决了这个问题:如果你向Tini发送信号,那么它也会向你的子进程发送同样的信号(在你的例子中是Jenkins)。

第二个问题是,一旦您的进程退出,Bash也会继续退出。如果您不小心,Bash可能会退出,退出代码为0,而您的进程实际上崩溃了(但0表示“一切正常”;这将导致Docker重启策略不符合您的预期)。因为您真正想要的可能是Bash返回与您的进程相同的退出代码。

请注意,您可以通过在Bash中创建信号处理程序来实际执行转发,并返回适当的退出代码来解决这个问题。另一方面,这需要做更多的工作,而添加Tini只是文档中的几行。

如果Jenkins以PID 1运行,那么它可能不会接收到您发送的信号!

这是PID 1进程中的微妙之处。与其他进程不同的是,PID 1没有默认的信号处理程序,这意味着如果Jenkins没有明确地为SIGTERM安装信号处理程序,那么该信号在发送时将被丢弃(而默认行为是终止该过程)。

Tini确实安装了显式信号处理程序(顺便说一下,是为了转发信号),所以这些信号不再被丢弃。相反,它们被发送到Jenkins,Jenkins并不像PID 1(Tini )那样运行,因此有默认的信号处理程序(注意:这不是Jenkins使用Tini的原因,Jenkins使用它来获取信号,但在RabbitMQ的镜像中是这个作用)。

 
posted @ 2021-12-18 17:04  mmgithub123  阅读(58)  评论(0)    收藏  举报