version: '3.7' services: server1: image: base-server container_name: server1 command: ["sh", "-c", "/scripts/start_services.sh"] environment: - VT_HOSTNAME=server1 - VT_TOPOLOGY=etcd:http://server1:2379 ports: - "15000:15000" - "15306:3306" networks: vitess-network: ipv4_address: 172.16.0.101 volumes: - ./scripts:/scripts - etcd-data:/var/lib/etcd # 修改挂载路径 server2: image: mysql-server container_name: server2 command: ["sh", "-c", "while ! nc -z server1 2379; do sleep 1; done; /scripts/init_master.sh"] environment: - VT_HOSTNAME=server2 - VT_TOPOLOGY=etcd:http://server1:2379 - VTDATAROOT=/vt/vtdataroot # 显式指定数据目录 networks: vitess-network: ipv4_address: 172.16.0.102 volumes: - ./scripts:/scripts - mysql-master:/vt/vtdataroot depends_on: - server1 server3: image: mysql-server container_name: server3 command: ["sh", "-c", "while ! nc -z server1 2379; do sleep 1; done; /scripts/init_replica.sh"] environment: - VT_HOSTNAME=server3 - VT_TOPOLOGY=etcd:http://server1:2379 - VTDATAROOT=/vt/vtdataroot networks: vitess-network: ipv4_address: 172.16.0.103 volumes: - ./scripts:/scripts - mysql-replica:/vt/vtdataroot depends_on: - server1 volumes: etcd-data: mysql-master: mysql-replica: networks: vitess-network: driver: bridge ipam: config: - subnet: 172.16.0.0/24 Dockerfile.base: FROM vitess/base USER root RUN chmod 777 /var/lib/etcd USER vitess Dockerfile.server: FROM vitess/base USER root RUN apt-get update && apt-get install -y netcat || yum install -y nc || apk add --no-cache gnu-netcat # 安装 etcdctl 和网络检测工具 RUN apt-get update && \ apt-get install -y curl && \ rm -rf /var/lib/apt/lists/* USER vitess start_services.sh: #!/bin/bash RUN apt-get update && apt-get install -y netcat || yum install -y nc || apk add --no-cache gnu-netcat # 启动 etcd、vtctld、vtgate etcd --data-dir /etcd & sleep 5 vtctld --topo_implementation etcd2 --topo_global_server_address http://localhost:2379 & vtgate --topo_implementation etcd2 --topo_global_server_address http://localhost:2379 --mysql_server_port 3306 & init_master.sh 和 init_replica.sh : #!/bin/bash # 启动 MySQL 从实例和 vttablet vttablet \ --topo_implementation etcd2 \ --topo_global_server_address server1:2379 \ --tablet-path "zone1-101" \ --init_keyspace "test_keyspace" \ --init_shard "0" \ --init_tablet_type "replica" \ --port 15002 \ --grpc_port 16002 \ --db_port 3306 2025-05-21 15:41:10.240 | /scripts/start_services.sh: line 3: RUN: command not found 2025-05-21 15:41:10.244 | /scripts/start_services.sh: line 3: yum: command not found 2025-05-21 15:41:10.248 | /scripts/start_services.sh: line 3: apk: command not found 2025-05-21 15:41:11.117 | {"level":"info","ts":"2025-05-21T07:41:11.109Z","caller":"etcdmain/etcd.go:73","msg":"Running: ","args":["etcd","--data-dir","/etcd"]} 2025-05-21 15:41:11.119 | {"level":"info","ts":"2025-05-21T07:41:11.117Z","caller":"embed/etcd.go:124","msg":"configuring peer listeners","listen-peer-urls":["http://localhost:2380"]} 2025-05-21 15:41:11.124 | {"level":"info","ts":"2025-05-21T07:41:11.124Z","caller":"embed/etcd.go:132","msg":"configuring client listeners","listen-client-urls":["http://localhost:2379"]} 2025-05-21 15:41:11.125 | {"level":"info","ts":"2025-05-21T07:41:11.125Z","caller":"embed/etcd.go:306","msg":"starting an etcd server","etcd-version":"3.5.6","git-sha":"cecbe35ce","go-version":"go1.16.15","go-os":"linux","go-arch":"amd64","max-cpu-set":12,"max-cpu-available":12,"member-initialized":false,"name":"default","data-dir":"/etcd","wal-dir":"","wal-dir-dedicated":"","member-dir":"/etcd/member","force-new-cluster":false,"heartbeat-interval":"100ms","election-timeout":"1s","initial-election-tick-advance":true,"snapshot-count":100000,"max-wals":5,"max-snapshots":5,"snapshot-catchup-entries":5000,"initial-advertise-peer-urls":["http://localhost:2380"],"listen-peer-urls":["http://localhost:2380"],"advertise-client-urls":["http://localhost:2379"],"listen-client-urls":["http://localhost:2379"],"listen-metrics-urls":[],"cors":["*"],"host-whitelist":["*"],"initial-cluster":"default=http://localhost:2380","initial-cluster-state":"new","initial-cluster-token":"etcd-cluster","quota-backend-bytes":2147483648,"max-request-bytes":1572864,"max-concurrent-streams":4294967295,"pre-vote":true,"initial-corrupt-check":false,"corrupt-check-time-interval":"0s","compact-check-time-enabled":false,"compact-check-time-interval":"1m0s","auto-compaction-mode":"periodic","auto-compaction-retention":"0s","auto-compaction-interval":"0s","discovery-url":"","discovery-proxy":"","downgrade-check-interval":"5s"} 2025-05-21 15:41:11.125 | {"level":"info","ts":"2025-05-21T07:41:11.125Z","caller":"embed/etcd.go:373","msg":"closing etcd server","name":"default","data-dir":"/etcd","advertise-peer-urls":["http://localhost:2380"],"advertise-client-urls":["http://localhost:2379"]} 2025-05-21 15:41:11.125 | {"level":"info","ts":"2025-05-21T07:41:11.125Z","caller":"embed/etcd.go:375","msg":"closed etcd server","name":"default","data-dir":"/etcd","advertise-peer-urls":["http://localhost:2380"],"advertise-client-urls":["http://localhost:2379"]} 2025-05-21 15:41:11.125 | {"level":"warn","ts":"2025-05-21T07:41:11.125Z","caller":"etcdmain/etcd.go:146","msg":"failed to start etcd","error":"cannot access data directory: mkdir /etcd: permission denied"} 2025-05-21 15:41:11.126 | {"level":"fatal","ts":"2025-05-21T07:41:11.125Z","caller":"etcdmain/etcd.go:204","msg":"discovery failed","error":"cannot access data directory: mkdir /etcd: permission denied","stacktrace":"go.etcd.io/etcd/server/v3/etcdmain.startEtcdOrProxyV2\n\tgo.etcd.io/etcd/server/v3/etcdmain/etcd.go:204\ngo.etcd.io/etcd/server/v3/etcdmain.Main\n\tgo.etcd.io/etcd/server/v3/etcdmain/main.go:40\nmain.main\n\tgo.etcd.io/etcd/server/v3/main.go:32\nruntime.main\n\truntime/proc.go:225"} nc: getaddrinfo for host "server1" port 2379: No address associated with hostname nc: getaddrinfo for host "server1" port 2379: No address associated with hostname nc: getaddrinfo for host "server1" port 2379: No address associated with hostname nc: getaddrinfo for host "server1" port 2379: No address associated with hostname nc: getaddrinfo for host "server1" port 2379: No address associated with hostname 启动失败
时间: 2025-05-30 12:04:15 浏览: 15
### 解决方案
#### 关于 `mkdir /etcd: permission denied` 错误
该错误表明宿主机上的 `/etcd` 数据目录没有足够的权限供 Docker 容器内的进程进行读写操作。可以通过以下方式解决:
1. **检查宿主机目录权限**
验证宿主机上 `/etcd` 目录是否存在,并确认其权限是否允许容器中的进程访问。如果不存在,则需手动创建并调整权限:
```bash
sudo mkdir -p /etcd
sudo chmod 777 /etcd
```
2. **修改挂载路径的权限**
如果已经存在 `/etcd` 目录,但仍然报错,可能是权限未正确分配给容器用户。可以尝试更改目录所属组和用户为当前登录用户:
```bash
sudo chown $(id -u):$(id -g) /etcd
```
3. **更新 Docker Compose 文件或启动命令**
确保在 Docker 启动时正确挂载了数据卷。例如,在 `docker-compose.yml` 中添加如下配置[^2]:
```yaml
services:
etcd:
image: quay.io/coreos/etcd:v3.5.1
volumes:
- /etcd:/etcd-data
```
或者通过命令行指定挂载选项:
```bash
docker run -d \
--name etcd \
-v /etcd:/etcd-data \
quay.io/coreos/etcd:v3.5.1
```
---
#### 关于 `nc` 无法解析 `server1` 主机名问题
此问题通常由 DNS 配置不正确引起,具体表现为容器内部无法识别外部定义的主机名。
1. **验证主机名解析功能**
使用宿主机上的工具测试 `server1` 是否可被解析:
```bash
nslookup server1
ping server1
```
若不可解析,说明需要进一步排查 DNS 设置。
2. **配置自定义 DNS 地址**
修改 Docker 的默认 DNS 设置以支持主机名解析。可以在 Docker Daemon 配置文件中加入公共 DNS(如 Google Public DNS),或者指向本地 DNS Server:
编辑 `/etc/docker/daemon.json` 并添加以下内容:
```json
{
"dns": ["8.8.8.8", "8.8.4.4"]
}
```
然后重启 Docker 服务使更改生效:
```bash
systemctl restart docker
```
3. **使用 Hosts 映射替代 DNS 查询**
对于固定的主机名(如 `server1`),可以直接将其记录写入容器的 `/etc/hosts` 文件。这可通过 `-h` 参数实现,也可以直接编辑 `docker-compose.yml` 文件[^3]:
```yaml
services:
etcd:
image: quay.io/coreos/etcd:v3.5.1
extra_hosts:
- "server1:<实际 IP>"
```
4. **确保网络模式兼容性**
如果容器运行在网络隔离模式下,默认情况下不会继承宿主机的网络栈。此时应考虑切换至桥接网络或其他共享网络模型。例如:
```yaml
network_mode: host
```
---
### 示例代码片段
以下是完整的 `docker-compose.yml` 示例,综合解决了上述两个问题:
```yaml
version: "3"
services:
etcd:
image: quay.io/coreos/etcd:v3.5.1
container_name: etcd
command: >
/bin/sh -c "
etcd --data-dir=/etcd-data &
sleep infinity
"
volumes:
- /etcd:/etcd-data
extra_hosts:
- "server1:192.168.1.10" # 替换为实际 IP 地址
networks:
default:
driver: bridge
networks:
default:
driver_opts:
com.docker.network.enable_ipv6: "false"
```
---
###
阅读全文
相关推荐


















