update
parent
bde246d984
commit
645534bef9
|
@ -1,5 +1,5 @@
|
|||
<p align="center">
|
||||
<a href="https://spring.io/projects/spring-boot" target="_blank" rel="noopener noreferrer">
|
||||
<a href="https://dunwu.github.io/linux-tutorial/" target="_blank" rel="noopener noreferrer">
|
||||
<img src="http://dunwu.test.upcdn.net/common/logo/linux.svg" alt="logo" width="100px">
|
||||
</a>
|
||||
</p>
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,5 @@
|
|||
FROM python:3.6-alpine
|
||||
ADD . /code
|
||||
WORKDIR /code
|
||||
RUN pip install redis flask
|
||||
CMD ["python", "app.py"]
|
|
@ -0,0 +1,13 @@
|
|||
from flask import Flask
|
||||
from redis import Redis
|
||||
|
||||
app = Flask(__name__)
|
||||
redis = Redis(host='redis', port=6379)
|
||||
|
||||
@app.route('/')
|
||||
def hello():
|
||||
count = redis.incr('hits')
|
||||
return 'Hello World! 该页面已被访问 {} 次。\n'.format(count)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", debug=True)
|
|
@ -0,0 +1,10 @@
|
|||
version: '3'
|
||||
services:
|
||||
|
||||
web:
|
||||
build: .
|
||||
ports:
|
||||
- "5000:5000"
|
||||
|
||||
redis:
|
||||
image: "redis:alpine"
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -x
|
||||
docker-compose up
|
|
@ -1,5 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# 常用变量库
|
||||
# @author Zhang Peng
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------ 颜色状态
|
||||
|
||||
# Regular Color
|
||||
|
@ -51,3 +56,48 @@ YES=0
|
|||
NO=1
|
||||
SUCCEED=0
|
||||
FAILED=1
|
||||
|
||||
# 显示打印日志的时间
|
||||
DATE=`date "+%Y-%m-%d %H:%M:%S"`
|
||||
# 那个用户在操作
|
||||
USER=$(whoami)
|
||||
|
||||
# ------------------------------------------------------------------------------ log
|
||||
|
||||
logInfo() {
|
||||
#($0脚本本身,$@将参数作为整体传输调用)
|
||||
echo "[${DATE}] [${USER}] [INFO] [$0] [$@] execute succeed." >> /var/log/shell.log
|
||||
}
|
||||
|
||||
logWarn() {
|
||||
#($0脚本本身,$@将参数作为整体传输调用)
|
||||
echo "[${DATE}] [${USER}] [WARN] [$0] [$@] execute succeed." >> /var/log/shell.log
|
||||
}
|
||||
|
||||
logError() {
|
||||
#($0脚本本身,$@将参数作为整体传输调用)
|
||||
echo "[${DATE}] [${USER}] [ERROR] [$0] [$@] execute failed." >> /var/log/shell.log
|
||||
}
|
||||
|
||||
printInfo() {
|
||||
echo -e "${C_B_GREEN}[INFO] $@${C_RESET}"
|
||||
}
|
||||
|
||||
printWarn() {
|
||||
echo -e "${C_B_YELLOW}[WARN] $@${C_RESET}"
|
||||
}
|
||||
|
||||
printError() {
|
||||
echo -e "${C_B_RED}[ERROR] $@${C_RESET}"
|
||||
}
|
||||
|
||||
callAndLog () {
|
||||
$*
|
||||
if [[ $? -eq ${SUCCEED} ]]; then
|
||||
logInfo "$@ succeed"
|
||||
echo -e "${C_B_GREEN}[INFO] [$0] [$@] execute succeed.${C_RESET}"
|
||||
else
|
||||
logError "$@ failed"
|
||||
echo -e "${C_B_RED}[ERROR] [$0] [$@] execute failed.${C_RESET}"
|
||||
fi
|
||||
}
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Git 基本操作脚本
|
||||
# @author Zhang Peng
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# 装载其它库
|
||||
ROOT=`dirname ${BASH_SOURCE[0]}`
|
||||
source ${ROOT}/env.sh
|
||||
|
@ -33,7 +38,7 @@ checkGit() {
|
|||
return ${NO}
|
||||
fi
|
||||
|
||||
printf "${C_B_B_YELLOW}${source} is invalid dir.${C_RESET}\n"
|
||||
printf "${C_B_YELLOW}${source} is invalid dir.${C_RESET}\n"
|
||||
return ${NO}
|
||||
}
|
||||
|
||||
|
@ -49,18 +54,18 @@ cloneOrPullGit() {
|
|||
local root=$5
|
||||
|
||||
if [[ ! ${repository} ]] || [[ ! ${group} ]] || [[ ! ${project} ]] || [[ ! ${branch} ]] || [[ ! ${root} ]]; then
|
||||
printf "${C_B_YELLOW}>>>> Please input root, group, project, branch.${C_RESET}\n"
|
||||
printf "${C_B_YELLOW}Please input root, group, project, branch.${C_RESET}\n"
|
||||
return ${FAILED}
|
||||
fi
|
||||
|
||||
if [[ ! -d "${root}" ]]; then
|
||||
printf "${C_B_YELLOW}>>>> ${root} is not directory.${C_RESET}\n"
|
||||
printf "${C_B_YELLOW}${root} is not directory.${C_RESET}\n"
|
||||
return ${FAILED}
|
||||
fi
|
||||
|
||||
local source=${root}/${group}/${project}
|
||||
printf "${C_B_CYAN}>>>> project directory is ${source}.${C_RESET}\n"
|
||||
printf "${C_B_CYAN}>>>> git url is ${repository}:${group}/${project}.git.${C_RESET}\n"
|
||||
printf "${C_B_MAGENTA}project directory is ${source}.${C_RESET}\n"
|
||||
printf "${C_B_MAGENTA}git url is ${repository}:${group}/${project}.git.${C_RESET}\n"
|
||||
mkdir -p ${root}/${group}
|
||||
|
||||
checkGit ${source}
|
||||
|
@ -73,21 +78,21 @@ cloneOrPullGit() {
|
|||
printf "${C_B_RED}<<<< git checkout ${branch} failed.${C_RESET}\n"
|
||||
return ${FAILED}
|
||||
fi
|
||||
printf "${C_B_GREEN}>>>> git checkout ${branch} succeed.${C_RESET}\n"
|
||||
printf "${C_B_GREEN}git checkout ${branch} succeed.${C_RESET}\n"
|
||||
|
||||
git reset --hard
|
||||
if [[ "${SUCCEED}" != "$?" ]]; then
|
||||
printf "${C_B_RED}<<<< git reset --hard failed.${C_RESET}\n"
|
||||
return ${FAILED}
|
||||
fi
|
||||
printf "${C_B_GREEN}>>>> git reset --hard succeed.${C_RESET}\n"
|
||||
printf "${C_B_GREEN}git reset --hard succeed.${C_RESET}\n"
|
||||
|
||||
git pull
|
||||
if [[ "${SUCCEED}" != "$?" ]]; then
|
||||
printf "${C_B_RED}<<<< git pull failed.${C_RESET}\n"
|
||||
return ${FAILED}
|
||||
fi
|
||||
printf "${C_B_GREEN}>>>> git pull succeed.${C_RESET}\n"
|
||||
printf "${C_B_GREEN}git pull succeed.${C_RESET}\n"
|
||||
else
|
||||
# 如果 ${source} 不是 git 项目,执行 clone 操作
|
||||
|
||||
|
@ -96,7 +101,7 @@ cloneOrPullGit() {
|
|||
printf "${C_B_RED}<<<< git clone ${project} failed.${C_RESET}\n"
|
||||
return ${FAILED}
|
||||
fi
|
||||
printf "${C_B_GREEN}>>>> git clone ${project} succeed.${C_RESET}\n"
|
||||
printf "${C_B_GREEN}git clone ${project} succeed.${C_RESET}\n"
|
||||
|
||||
cd ${source} || return ${FAILED}
|
||||
|
||||
|
@ -105,8 +110,9 @@ cloneOrPullGit() {
|
|||
printf "${C_B_RED}<<<< git checkout ${branch} failed.${C_RESET}\n"
|
||||
return ${FAILED}
|
||||
fi
|
||||
printf "${C_B_GREEN}>>>> git checkout ${branch} succeed.${C_RESET}\n"
|
||||
printf "${C_B_GREEN}git checkout ${branch} succeed.${C_RESET}\n"
|
||||
fi
|
||||
|
||||
printf "${C_B_GREEN}Clone or pull git project [$2/$3:$4] succeed.${C_RESET}\n"
|
||||
return ${SUCCEED}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Java 应用运维脚本
|
||||
# @author Zhang Peng
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------ env preparation
|
||||
# load libs
|
||||
CURRENT_PATH=`dirname ${BASH_SOURCE[0]}`
|
||||
source ${CURRENT_PATH}/env.sh
|
||||
|
||||
# ------------------------------------------------------------------------------ functions
|
||||
|
||||
stopServer() {
|
||||
if [[ ! $1 ]]; then
|
||||
printError "please input java app name"
|
||||
return ${FAILED}
|
||||
fi
|
||||
|
||||
local javaAppName=$1
|
||||
local pid=`jps | grep ${javaAppName} | awk '{print $1}'`
|
||||
if [[ -n "${pid}" ]]; then
|
||||
kill -9 ${pid}
|
||||
if [[ $? -eq ${SUCCEED} ]]; then
|
||||
printInfo "stop ${javaAppName} succeed"
|
||||
return ${SUCCEED}
|
||||
else
|
||||
printError "stop ${javaAppName} failed"
|
||||
return ${FAILED}
|
||||
fi
|
||||
else
|
||||
printWarn "${javaAppName} is not running"
|
||||
return ${SUCCEED}
|
||||
fi
|
||||
}
|
||||
|
||||
startServer() {
|
||||
if [[ ! $1 ]]; then
|
||||
printError "please input java app name"
|
||||
return ${FAILED}
|
||||
fi
|
||||
|
||||
# >>>> 1. check java app is started or not
|
||||
# >>>> 1.1. exit script if the app is started
|
||||
local javaAppName=$1
|
||||
local pid=`jps | grep ${javaAppName} | awk '{print $1}'`
|
||||
if [[ -n "${pid}" ]]; then
|
||||
printInfo "${javaAppName} is started, PID: ${pid}"
|
||||
return ${SUCCEED}
|
||||
fi
|
||||
|
||||
# >>>> 2. package options
|
||||
# GC OPTS
|
||||
local javaOptions="-server -Xms1g -Xmx2g -Xss256k"
|
||||
javaOptions="${javaOptions} -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:NewRatio=4"
|
||||
|
||||
# GC LOG OPTS
|
||||
javaOptions="${javaOptions} -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps"
|
||||
javaOptions="${javaOptions} -verbose:gc -Xloggc:${LOG_PATH}/${javaAppName}.gc.log"
|
||||
javaOptions="${javaOptions} -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M"
|
||||
|
||||
# Heap Dump OPTS
|
||||
javaOptions="${javaOptions} -XX:-OmitStackTraceInFastThrow -XX:+HeapDumpOnOutOfMemoryError"
|
||||
javaOptions="${javaOptions} -XX:HeapDumpPath=${LOG_PATH}/${javaAppName}.heapdump.hprof"
|
||||
|
||||
# APP OPTS
|
||||
javaOptions="${javaOptions} -Dsun.net.inetaddr.ttl=60 -Djava.net.preferIPv4Stack=true -Dfile.encoding=UTF-8"
|
||||
if [[ ${PROFILE} ]]; then
|
||||
javaOptions="${javaOptions} -Dspring.profiles.active=${PROFILE}"
|
||||
fi
|
||||
|
||||
# DEBUG OPTS
|
||||
if [[ "${DEBUG}" == "on" ]]; then
|
||||
# JMX OPTS
|
||||
local ip=$(ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d '/')
|
||||
local jmxPort=$(expr 10000 + ${PORT})
|
||||
javaOptions="${javaOptions} -Dcom.sun.management.jmxremote=true"
|
||||
javaOptions="${javaOptions} -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false"
|
||||
javaOptions="${javaOptions} -Djava.rmi.server.hostname=${ip} -Dcom.sun.management.jmxremote.port=${jmxPort}"
|
||||
|
||||
# Remote Debug
|
||||
local debugPort=$(expr 20000 + ${PORT})
|
||||
javaOptions="${javaOptions} -Xdebug -Xnoagent -Djava.compiler=NONE"
|
||||
javaOptions="${javaOptions} -Xrunjdwp:transport=dt_socket,address=${debugPort},server=y,suspend=n"
|
||||
fi
|
||||
|
||||
# CLASSPATH
|
||||
local appOptions="-classpath ${ROOT_PATH}/lib/* -Dlogging.config=file:${ROOT_PATH}/config/logback.dev.xml"
|
||||
appOptions="${appOptions} --spring.config.location=classpath:/,classpath:/config/,file:${ROOT_PATH},file:${ROOT_PATH}/config/"
|
||||
if [[ ${PORT} ]]; then
|
||||
appOptions="${appOptions} --server.port=${PORT}"
|
||||
fi
|
||||
|
||||
# >>>> 3. create log dir and console log file
|
||||
mkdir -p ${LOG_PATH}
|
||||
if [[ ! -f ${CONSOLE_LOG} ]]; then
|
||||
touch ${CONSOLE_LOG}
|
||||
fi
|
||||
|
||||
# >>>> 4. start java app
|
||||
printInfo "starting ${javaAppName}, execute cli: "
|
||||
printInfo "nohup java ${javaOptions} -jar ${ROOT_PATH}/${javaAppName}.jar ${appOptions} >> ${CONSOLE_LOG} 2>&1 &"
|
||||
nohup java ${javaOptions} -jar ${ROOT_PATH}/${javaAppName}.jar ${appOptions} >> ${CONSOLE_LOG} 2>&1 &
|
||||
|
||||
# >>>> 5. check java app is started or not
|
||||
local pid=`jps | grep ${javaAppName} | awk '{print $1}'`
|
||||
if [[ -n "${pid}" ]]; then
|
||||
printInfo "start ${javaAppName} succeed, PID: ${pid}"
|
||||
return ${SUCCEED}
|
||||
else
|
||||
printError "start ${javaAppName} failed"
|
||||
return ${FAILED}
|
||||
fi
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------ main
|
||||
export LANG="zh_CN.UTF-8"
|
||||
ROOT_PATH=$(cd ${CURRENT_PATH}/..; pwd)
|
||||
|
||||
APP_NAME=java-app
|
||||
LOG_PATH=/var/log/myapp
|
||||
CONSOLE_LOG=${LOG_PATH}/${APP_NAME}.console.log
|
||||
|
||||
PORT=8888
|
||||
PROFILE=dev
|
||||
DEBUG=off
|
||||
|
||||
startServer ${APP_NAME}
|
||||
#stopServer ${APP_NAME}
|
||||
if [[ $? -eq ${SUCCEED} ]]; then
|
||||
exit ${SUCCEED}
|
||||
else
|
||||
exit ${FAILED}
|
||||
fi
|
|
@ -0,0 +1,66 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# maven 项目操作脚本
|
||||
# @author Zhang Peng
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# 装载其它库
|
||||
ROOT=`dirname ${BASH_SOURCE[0]}`
|
||||
source ${ROOT}/env.sh
|
||||
|
||||
mavenBuild() {
|
||||
local source=$1
|
||||
mavenCheck $1
|
||||
if [[ "${SUCCEED}" != "$?" ]]; then
|
||||
return ${FAILED}
|
||||
fi
|
||||
|
||||
if [[ -d "${source}" ]]; then
|
||||
cd ${source}
|
||||
if [[ -f "${source}/settings.xml" ]]; then
|
||||
callAndLog "mvn clean install -B -U -s ${source}/settings.xml -Dmaven.test.skip=true"
|
||||
else
|
||||
callAndLog "mvn clean install -DskipTests=true -B -U"
|
||||
fi
|
||||
cd -
|
||||
return ${SUCCEED}
|
||||
else
|
||||
printf "${C_B_RED}please input valid maven project path.${C_RESET}\n"
|
||||
return ${FAILED}
|
||||
fi
|
||||
}
|
||||
|
||||
mavenCheck() {
|
||||
local source=$1
|
||||
if [[ -d "${source}" ]]; then
|
||||
cd ${source}
|
||||
if [[ -f "${source}/pom.xml" ]]; then
|
||||
return ${YES}
|
||||
else
|
||||
printf "${C_B_RED}pom.xml is not exists.${C_RESET}\n"
|
||||
return ${NO}
|
||||
fi
|
||||
cd -
|
||||
return ${YES}
|
||||
else
|
||||
printf "${C_B_RED}please input valid maven project path.${C_RESET}\n"
|
||||
return ${NO}
|
||||
fi
|
||||
}
|
||||
|
||||
##################################### MAIN #####################################
|
||||
printf "\n${C_B_GREEN}>>>> maven build begin.${C_RESET}\n\n"
|
||||
|
||||
printf "${C_B_MAGENTA}Current path is ${ROOT}.${C_RESET}\n"
|
||||
|
||||
mavenBuild ${ROOT}/..
|
||||
r1=$?
|
||||
|
||||
if [[ "${r1}" == "${SUCCEED}" ]]; then
|
||||
printf "\n${C_B_GREEN}<<<< maven build succeed.${C_RESET}\n\n"
|
||||
exit ${SUCCEED}
|
||||
else
|
||||
printf "\n${C_B_RED}<<<< maven build failed.${C_RESET}\n\n"
|
||||
exit ${FAILED}
|
||||
fi
|
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# ----------------------------------------------------------------------------------
|
||||
# 控制台颜色
|
||||
BLACK="\033[1;30m"
|
||||
RED="\033[1;31m"
|
||||
GREEN="\033[1;32m"
|
||||
YELLOW="\033[1;33m"
|
||||
BLUE="\033[1;34m"
|
||||
PURPLE="\033[1;35m"
|
||||
CYAN="\033[1;36m"
|
||||
RESET="$(tput sgr0)"
|
||||
# ----------------------------------------------------------------------------------
|
||||
|
||||
printf "${PURPLE}"
|
||||
cat << EOF
|
||||
# ----------------------------------------------------------------------------------
|
||||
# XXX 脚本
|
||||
# @author: Zhang Peng
|
||||
# ----------------------------------------------------------------------------------
|
||||
EOF
|
||||
printf "${RESET}"
|
||||
|
||||
printf "${BLUE}>>>>>>>> begin.\n${RESET}"
|
||||
|
||||
printf "${GREEN}[OK]\n${RESET}"
|
||||
printf "${RED}[ERROR]\n${RESET}"
|
||||
|
||||
printf "${BLUE}<<<<<<<< end.\n${RESET}"
|
||||
|
||||
IP=`ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d '/'`
|
|
@ -28,10 +28,9 @@ doCloneOrPullGit ${REPOSITORY} turnon nginx-tutorial master ${ROOT}
|
|||
r2=$?
|
||||
|
||||
if [[ "${r1}" == "${SUCCEED}" && "${r2}" == "${SUCCEED}" ]]; then
|
||||
printf "\n${C_GREEN}Succeed.${C_RESET}\n"
|
||||
printf "\n${C_B_GREEN}<<<< Init workspace Succeed.${C_RESET}\n\n"
|
||||
exit ${SUCCEED}
|
||||
else
|
||||
printf "\n${C_RED}Failed.${C_RESET}\n"
|
||||
printf "\n${C_B_RED}<<<< Init workspace Failed.${C_RESET}\n\n"
|
||||
exit ${FAILED}
|
||||
fi
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
- [RocketMQ 安装](#rocketmq-安装)
|
||||
- [Nacos 安装](#nacos-安装)
|
||||
- [ZooKeeper 安装](#zookeeper-安装)
|
||||
- [Nginx 安装](#nginx-安装)
|
||||
- [Nginx 运维](#nginx-安装)
|
||||
- [Fastdfs 安装](#fastdfs-安装)
|
||||
- [Docker 安装](#docker-安装)
|
||||
|
||||
|
@ -190,7 +190,7 @@ curl -o- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/zoo
|
|||
wget -qO- https://gitee.com/turnon/linux-tutorial/raw/master/codes/linux/soft/zookeeper-install.sh | bash
|
||||
```
|
||||
|
||||
## Nginx 安装
|
||||
## Nginx 运维
|
||||
|
||||
**安装说明**
|
||||
|
||||
|
|
|
@ -33,16 +33,15 @@ sudo yum remove docker \
|
|||
docker-latest \
|
||||
docker-latest-logrotate \
|
||||
docker-logrotate \
|
||||
docker-selinux \
|
||||
docker-engine-selinux \
|
||||
docker-engine
|
||||
|
||||
# install required libs
|
||||
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
|
||||
# add docker yum repo
|
||||
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
|
||||
sudo yum makecache fast
|
||||
# install docker
|
||||
sudo yum -y install docker-ce
|
||||
sudo yum install docker-ce docker-ce-cli containerd.io
|
||||
sudo systemctl start docker
|
||||
docker version
|
||||
printf "${GREEN}<<<<<<<< install docker end.${RESET}\n"
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
# linux-tutorial
|
||||
<p align="center">
|
||||
<a href="https://dunwu.github.io/linux-tutorial/" target="_blank" rel="noopener noreferrer">
|
||||
<img src="http://dunwu.test.upcdn.net/common/logo/linux.svg" alt="logo" width="100px">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://badgen.net/github/license/dunwu/linux-tutorial" alt="license">
|
||||
</p>
|
||||
|
||||
<h1 align="center">linux-tutorial</h1>
|
||||
|
||||
> 📚 **linux-tutorial** 是一个 Linux 教程。
|
||||
>
|
||||
|
|
|
@ -58,9 +58,7 @@
|
|||
},
|
||||
"sharing": {
|
||||
"weibo": true,
|
||||
"all": [
|
||||
"weibo"
|
||||
]
|
||||
"all": ["weibo"]
|
||||
},
|
||||
"tbfed-pagefooter": {
|
||||
"copyright": "Copyright © Zhang Peng 2017",
|
||||
|
|
|
@ -8,8 +8,9 @@
|
|||
|
||||
- **官方**
|
||||
- [Docker 官网](http://www.docker.com)
|
||||
- [Docker Github](https://github.com/moby/moby)
|
||||
- [Docker 官方文档](https://docs.docker.com/)
|
||||
- [Docker Github](https://github.com/moby/moby)
|
||||
- [Docker Compose Github](https://github.com/docker/compose)
|
||||
- [Docker Hub](https://hub.docker.com/)
|
||||
- [Docker 开源](https://www.docker.com/community/open-source)
|
||||
- **资源整理**
|
||||
|
|
|
@ -308,6 +308,48 @@ $ docker run --rm -it --net iptastic --ip 203.0.113.2 nginx
|
|||
$ curl 203.0.113.2
|
||||
```
|
||||
|
||||
## 暴露端口(Exposing ports)
|
||||
|
||||
通过宿主容器暴露输入端口相当 [繁琐但有效的](https://docs.docker.com/engine/reference/run/#expose-incoming-ports)。
|
||||
|
||||
例如使用 `-p` 将容器端口映射到宿主端口上(只使用本地主机 (localhost) 接口):
|
||||
|
||||
```
|
||||
docker run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT --name CONTAINER -t someimage
|
||||
```
|
||||
|
||||
你可以使用 [EXPOSE](https://docs.docker.com/engine/reference/builder/#expose) 告知 Docker,该容器在运行时监听指定的端口:
|
||||
|
||||
```
|
||||
EXPOSE <CONTAINERPORT>
|
||||
```
|
||||
|
||||
但是注意 EXPOSE 并不会直接暴露端口,你需要用参数 `-p` 。比如说你要在 localhost 上暴露容器的端口:
|
||||
|
||||
```
|
||||
iptables -t nat -A DOCKER -p tcp --dport <LOCALHOSTPORT> -j DNAT --to-destination <CONTAINERIP>:<PORT>
|
||||
```
|
||||
|
||||
如果你是在 Virtualbox 中运行 Docker,那么你需要配置端口转发 (forward the port)。使用 [forwarded_port](https://docs.vagrantup.com/v2/networking/forwarded_ports.html) 在 Vagrantfile 上配置暴露的端口范围,这样你就可以动态地映射了:
|
||||
|
||||
```
|
||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
...
|
||||
|
||||
(49000..49900).each do |port|
|
||||
config.vm.network :forwarded_port, :host => port, :guest => port
|
||||
end
|
||||
|
||||
...
|
||||
end
|
||||
```
|
||||
|
||||
如果你忘记了将什么端口映射到宿主机上的话,可使用 `docker port` 查看:
|
||||
|
||||
```
|
||||
docker port CONTAINER $CONTAINERPORT
|
||||
```
|
||||
|
||||
## 仓管中心和仓库(Registry & Repository)
|
||||
|
||||
仓库 (repository) 是 _被托管(hosted)_ 的已命名镜像 (tagged images) 的集合,这组镜像用于构建容器文件系统。
|
||||
|
@ -411,19 +453,27 @@ $ALIAS_PORT_1337_TCP_ADDR
|
|||
|
||||
通常,Docker 容器(亦可理解为「服务」)之间的链接,是「服务发现」的一个子集。如果你打算在生产中大规模使用 Docker,这将是一个很大的问题。请参阅[The Docker Ecosystem: Service Discovery and Distributed Configuration Stores](https://www.digitalocean.com/community/tutorials/the-docker-ecosystem-service-discovery-and-distributed-configuration-stores) 获取更多信息。
|
||||
|
||||
## 卷标(Volumes)
|
||||
## 卷标(Volumes)和挂载
|
||||
|
||||
### 卷标
|
||||
|
||||
Docker 的卷标 (volumes) 是 [独立的文件系统](https://docs.docker.com/engine/tutorials/dockervolumes/)。它们并非必须连接到特定的容器上。
|
||||
|
||||
### 生命周期
|
||||
`数据卷` 是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:
|
||||
|
||||
- [`docker volume create`](https://docs.docker.com/engine/reference/commandline/volume_create/)
|
||||
- [`docker volume rm`](https://docs.docker.com/engine/reference/commandline/volume_rm/)
|
||||
- `数据卷` 可以在容器之间共享和重用
|
||||
- 对 `数据卷` 的修改会立马生效
|
||||
- 对 `数据卷` 的更新,不会影响镜像
|
||||
- `数据卷` 默认会一直存在,即使容器被删除
|
||||
|
||||
### 信息
|
||||
卷标相关命令:
|
||||
|
||||
- [`docker volume ls`](https://docs.docker.com/engine/reference/commandline/volume_ls/)
|
||||
- [`docker volume inspect`](https://docs.docker.com/engine/reference/commandline/volume_inspect/)
|
||||
- [`docker volume create`](https://docs.docker.com/engine/reference/commandline/volume_create/) - 创建卷标
|
||||
- [`docker volume rm`](https://docs.docker.com/engine/reference/commandline/volume_rm/) - 删除卷标
|
||||
|
||||
- [`docker volume ls`](https://docs.docker.com/engine/reference/commandline/volume_ls/) - 查看卷标
|
||||
- [`docker volume inspect`](https://docs.docker.com/engine/reference/commandline/volume_inspect/) - 查看数据卷的具体信息
|
||||
- [`docker volume prune`](https://docs.docker.com/engine/reference/commandline/volume_prune/) - 清理无主的数据卷
|
||||
|
||||
卷标在不能使用链接(只有 TCP/IP)的情况下非常有用。例如,如果你有两个 Docker 实例需要通讯并在文件系统上留下记录。
|
||||
|
||||
|
@ -445,47 +495,11 @@ docker run -v /Users/wsargent/myapp/src:/src
|
|||
|
||||
记得,[文件也可以被挂载为卷标](https://github.com/wsargent/docker-cheat-sheet/tree/master/zh-cn#将文件挂载为卷标)。
|
||||
|
||||
## 暴露端口(Exposing ports)
|
||||
### 挂载
|
||||
|
||||
通过宿主容器暴露输入端口相当 [繁琐但有效的](https://docs.docker.com/engine/reference/run/#expose-incoming-ports)。
|
||||
使用 `--mount` 标记可以指定挂载一个本地主机的目录到容器中去。
|
||||
|
||||
例如使用 `-p` 将容器端口映射到宿主端口上(只使用本地主机 (localhost) 接口):
|
||||
|
||||
```
|
||||
docker run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT --name CONTAINER -t someimage
|
||||
```
|
||||
|
||||
你可以使用 [EXPOSE](https://docs.docker.com/engine/reference/builder/#expose) 告知 Docker,该容器在运行时监听指定的端口:
|
||||
|
||||
```
|
||||
EXPOSE <CONTAINERPORT>
|
||||
```
|
||||
|
||||
但是注意 EXPOSE 并不会直接暴露端口,你需要用参数 `-p` 。比如说你要在 localhost 上暴露容器的端口:
|
||||
|
||||
```
|
||||
iptables -t nat -A DOCKER -p tcp --dport <LOCALHOSTPORT> -j DNAT --to-destination <CONTAINERIP>:<PORT>
|
||||
```
|
||||
|
||||
如果你是在 Virtualbox 中运行 Docker,那么你需要配置端口转发 (forward the port)。使用 [forwarded_port](https://docs.vagrantup.com/v2/networking/forwarded_ports.html) 在 Vagrantfile 上配置暴露的端口范围,这样你就可以动态地映射了:
|
||||
|
||||
```
|
||||
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||
...
|
||||
|
||||
(49000..49900).each do |port|
|
||||
config.vm.network :forwarded_port, :host => port, :guest => port
|
||||
end
|
||||
|
||||
...
|
||||
end
|
||||
```
|
||||
|
||||
如果你忘记了将什么端口映射到宿主机上的话,可使用 `docker port` 查看:
|
||||
|
||||
```
|
||||
docker port CONTAINER $CONTAINERPORT
|
||||
```
|
||||
在用 `docker run` 命令的时候,使用 `--mount` 标记来将 `数据卷` 挂载到容器里。在一次 `docker run` 中可以挂载多个 `数据卷`。
|
||||
|
||||
## 最佳实践
|
||||
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
# Docker Compose
|
||||
|
||||
> [compose](https://github.com/docker/compose) 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。从功能上看,跟 `OpenStack` 中的 `Heat` 十分类似。
|
||||
|
||||
## 一、Compose 简介
|
||||
|
||||
**`Compose` 的定位是:定义和运行多个 Docker 容器的应用**。 使用一个 `Dockerfile` 模板文件,可以让用户很方便的定义一个单独的应用容器。然而,在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡容器等。
|
||||
|
||||
`Compose` 恰好满足了这样的需求。它允许用户通过一个单独的 `docker-compose.yml` 模板文件(YAML 格式)来定义一组相关联的应用容器为一个项目(project)。
|
||||
|
||||
`Compose` 中有两个重要的概念:
|
||||
|
||||
- **服务 (`service`)**:一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。
|
||||
- **项目 (`project`)**:由一组关联的应用容器组成的一个完整业务单元,在 `docker-compose.yml` 文件中定义。
|
||||
|
||||
`Compose` 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。
|
||||
|
||||
## 二、安装卸载
|
||||
|
||||
`Compose` 支持 Linux、macOS、Windows10 三大平台。
|
||||
|
||||
Linux 安装方式:
|
||||
|
||||
```bash
|
||||
sudo curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
|
||||
sudo chmod +x /usr/local/bin/docker-compose
|
||||
```
|
||||
|
||||
> :bell: 详情请参考:[Install Docker Compose](https://docs.docker.com/compose/install/)
|
||||
|
||||
## 三、快速入门
|
||||
|
||||
### web 应用
|
||||
|
||||
新建文件夹,在该目录中编写 `app.py` 文件
|
||||
|
||||
```python
|
||||
from flask import Flask
|
||||
from redis import Redis
|
||||
|
||||
app = Flask(__name__)
|
||||
redis = Redis(host='redis', port=6379)
|
||||
|
||||
@app.route('/')
|
||||
def hello():
|
||||
count = redis.incr('hits')
|
||||
return 'Hello World! 该页面已被访问 {} 次。\n'.format(count)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(host="0.0.0.0", debug=True)
|
||||
```
|
||||
|
||||
### Dockerfile
|
||||
|
||||
编写 `Dockerfile` 文件,内容为
|
||||
|
||||
```docker
|
||||
FROM python:3.6-alpine
|
||||
ADD . /code
|
||||
WORKDIR /code
|
||||
RUN pip install redis flask
|
||||
CMD ["python", "app.py"]
|
||||
```
|
||||
|
||||
### docker-compose.yml
|
||||
|
||||
编写 `docker-compose.yml` 文件,这个是 Compose 使用的主模板文件。
|
||||
|
||||
```yaml
|
||||
version: '3'
|
||||
services:
|
||||
|
||||
web:
|
||||
build: .
|
||||
ports:
|
||||
- "5000:5000"
|
||||
|
||||
redis:
|
||||
image: "redis:alpine"
|
||||
```
|
||||
|
||||
### 运行 compose 项目
|
||||
|
||||
```bash
|
||||
$ docker-compose up
|
||||
```
|
||||
|
||||
此时访问本地 `5000` 端口,每次刷新页面,计数就会加 1。
|
||||
|
||||
## 四、命令
|
||||
|
||||
> :bell: 请参考:
|
||||
>
|
||||
> - [Compose 官方命令说明文档](https://docs.docker.com/compose/reference/)
|
||||
> - [Compose 命令说明中文文档](https://yeasy.gitbooks.io/docker_practice/content/compose/commands.html)
|
||||
|
||||
## 五、模板文件
|
||||
|
||||
> `docker-compose.yml` 文件是 Docker Compose 的模板文件,其作用类似于 Dockerfile 和 Docker。
|
||||
|
||||
[docker-compose.yml 支持的默认环境变量官方文档](https://docs.docker.com/compose/env-file/)
|
||||
|
||||
## 参考资料
|
||||
|
||||
- **官方**
|
||||
- [Docker Compose Github](https://github.com/docker/compose)
|
||||
- [Docker Compose 官方文档](https://docs.docker.com/compose/)
|
||||
- **教程**
|
||||
- [Docker — 从入门到实践 - Docker Compose 项目]( https://yeasy.gitbooks.io/docker_practice/content/compose/ )
|
||||
|
|
@ -21,7 +21,15 @@
|
|||
|
||||
<!-- /TOC -->
|
||||
|
||||
## 一、Dockerfile 指令
|
||||
## 一、Dockerfile 简介
|
||||
|
||||
Docker 镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本,用这个脚本来构建、定制镜像,那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。
|
||||
|
||||
Dockerfile 是一个文本文件,其内包含了一条条的 **指令(Instruction)**,每一条指令构建一层,因此每一条指令的内容,就是描述该层应当如何构建。
|
||||
|
||||
### 使用 Dockerfile 构建镜像
|
||||
|
||||
## 二、Dockerfile 指令详解
|
||||
|
||||
### FROM(指定基础镜像)
|
||||
|
||||
|
@ -658,6 +666,8 @@ FROM my-node
|
|||
|
||||
是的,只有这么一行。当在各个项目目录中,用这个只有一行的 `Dockerfile` 构建镜像时,之前基础镜像的那三行 `ONBUILD` 就会开始执行,成功的将当前项目的代码复制进镜像、并且针对本项目执行 `npm install`,生成应用镜像。
|
||||
|
||||
## 二、最佳实践
|
||||
|
||||
|
||||
|
||||
有任何的问题或建议,欢迎给我留言 :laughing:
|
||||
|
@ -665,6 +675,6 @@ FROM my-node
|
|||
## 参考资料
|
||||
|
||||
- [Dockerfie 官方文档](https://docs.docker.com/engine/reference/builder/)
|
||||
- [Dockerfile 最佳实践文档](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)
|
||||
- [Best practices for writing Dockerfiles](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)
|
||||
- [Docker 官方镜像 Dockerfile](https://github.com/docker-library/docs)
|
||||
- [Dockerfile 指令详解](https://yeasy.gitbooks.io/docker_practice/content/image/dockerfile/)
|
||||
|
|
|
@ -117,7 +117,7 @@ $ sudo service docker start
|
|||
$ sudo systemctl start docker
|
||||
```
|
||||
|
||||
## 三、hello world 实例
|
||||
## 三、Hello World 实例
|
||||
|
||||
下面,我们通过最简单的 image 文件"[hello world"](https://hub.docker.com/r/library/hello-world/),感受一下 Docker。
|
||||
|
||||
|
@ -354,3 +354,4 @@ $ sudo systemctl start docker
|
|||
## 参考资料
|
||||
|
||||
- [Docker 入门教程](https://www.ruanyifeng.com/blog/2018/02/docker-tutorial.html)
|
||||
- [Docker — 从入门到实践](https://github.com/yeasy/docker_practice)
|
Loading…
Reference in New Issue