Như @Connor McCarthy đã nói, trong khi chờ đợi Amazon đưa ra giải pháp tốt hơn cho các khóa vĩnh viễn hơn, trong lúc này, chúng ta cần phải tự tạo các khóa trên máy chủ Jenkins.
Giải pháp của tôi là có một công việc định kỳ cập nhật thông tin đăng nhập Jenkins cho ECR cứ sau 12 giờ, sử dụng API Groovy. Điều này dựa trên câu trả lời rất chi tiết này , mặc dù tôi đã làm một vài điều khác biệt và tôi phải sửa đổi kịch bản.
Các bước:
- Đảm bảo chủ Jenkins của bạn có thể truy cập API AWS cần thiết. Trong thiết lập của tôi, chủ Jenkins đang chạy trên EC2 với vai trò IAM, vì vậy tôi chỉ cần thêm quyền
ecr:GetAuthorizationToken
cho vai trò máy chủ. [ cập nhật ] Để hoàn thành bất kỳ lần đẩy nào, bạn cũng cần cấp các quyền này : ecr:InitiateLayerUpload, ecr:UploadLayerPart, ecr:CompleteLayerUpload, ecr:BatchCheckLayerAvailability, ecr:PutImage
. Amazon có một chính sách tích hợp cung cấp các khả năng này, được gọi là AmazonEC2ContainerRegistryPowerUser
.
- Đảm bảo rằng AWS CLI được cài đặt trên bản gốc. Trong thiết lập của tôi, với bản gốc đang chạy trong bộ chứa docker debian, tôi vừa thêm bước xây dựng shell này vào công việc tạo khóa:
dpkg -l python-pip >/dev/null 2>&1 || sudo apt-get install python-pip -y; pip list 2>/dev/null | grep -q awscli || pip install awscli
- Cài đặt plugin Groovy cho phép bạn chạy tập lệnh Groovy như một phần của hệ thống Jenkins.
- Trong màn hình thông tin đăng nhập, hãy tìm khóa AWS ECR của bạn, nhấp vào "Nâng cao" và ghi lại "ID" của nó. Trong ví dụ này tôi sẽ giả sử nó là "12345".
- Tạo một công việc mới, với thời gian khởi động 12 giờ định kỳ và thêm bước xây dựng "tập lệnh Groovy hệ thống" với tập lệnh sau:
import jenkins.model.*
import com.cloudbees.plugins.credentials.impl.UsernamePasswordCredentialsImpl
def changePassword = { username, new_password ->
def creds = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
com.cloudbees.plugins.credentials.common.StandardUsernameCredentials.class,
Jenkins.instance)
def c = creds.findResult { it.username == username ? it : null }
if ( c ) {
println "found credential ${c.id} for username ${c.username}"
def credentials_store = Jenkins.instance.getExtensionList(
'com.cloudbees.plugins.credentials.SystemCredentialsProvider'
)[0].getStore()
def result = credentials_store.updateCredentials(
com.cloudbees.plugins.credentials.domains.Domain.global(),
c,
new UsernamePasswordCredentialsImpl(c.scope, "12345", c.description, c.username, new_password))
if (result) {
println "password changed for ${username}"
} else {
println "failed to change password for ${username}"
}
} else {
println "could not find credential for ${username}"
}
}
println "calling AWS for docker login"
def prs = "/usr/local/bin/aws --region us-east-1 ecr get-login".execute()
prs.waitFor()
def logintext = prs.text
if (prs.exitValue()) {
println "Got error from aws cli"
throw new Exception()
} else {
def password = logintext.split(" ")[5]
println "Updating password"
changePassword('AWS', password)
}
Xin lưu ý:
- việc sử dụng chuỗi được mã hóa cứng
"AWS"
làm tên người dùng cho thông tin đăng nhập ECR - đây là cách ECR hoạt động, nhưng nếu bạn có nhiều thông tin đăng nhập với tên người dùng "AWS", thì bạn cần cập nhật tập lệnh để xác định thông tin đăng nhập dựa trên trường mô tả hoặc một cái gì đó.
- Bạn phải sử dụng ID thực của khóa ECR thực của mình trong tập lệnh, bởi vì API cho thông tin đăng nhập thay thế đối tượng thông tin xác thực bằng một đối tượng mới thay vì chỉ cập nhật nó và ràng buộc giữa bước xây dựng Docker và khóa là bởi ID. Nếu bạn sử dụng giá trị
null
cho ID (như trong câu trả lời tôi đã liên kết trước đó), thì một ID mới sẽ được tạo và cài đặt thông tin đăng nhập trong bước xây dựng docker sẽ bị mất.
Và đó là - tập lệnh sẽ có thể chạy cứ sau 12 giờ và làm mới thông tin đăng nhập ECR và chúng tôi có thể tiếp tục sử dụng các trình cắm Docker.