Roman Yaremchuk and Andriy Yarmolenko put Ukraine two goals up after 27 minutes.
Although Ronaldo scored his landmark goal from the penalty spot in the 72nd minute and Taras Stepanenko was sent off, Ukraine held on to secure first place in Group B.
Ukraine join already qualified Poland, Russia, Italy and Belgium at next summer’s finals, while second-placed Portugal, who are eight points behind Ukraine, have Serbia just a point behind them with two matches remaning after they beat Lithuania 2-1.
“There are days like these, when the ball just doesn’t want to go in,” said Portuguese midfielder Danilo. “No need to do the maths now: we just need to win the next two games to reach Euro 2020.”
Yaremchuk pounced from close range in the sixth minute. The centre forward reacted fastest after Rui Patricio dived to parry Serhiy Kryvtsov’s header from a corner, and poke the ball across the line.
Yarmolenko added the second when outpaced the Portuguese defence to finish a swift counter attack with a low, crisp first-time shot.
Portugal dominated the second half and finally achieved a breakthrough when Stepanenko blocked a shot with his arm, receiving his marching orders before Ronaldo blasted home the penalty to make it 700 goals for club and country.
The goal was his 95th for Portugal. The 34-year-old is now just 14 goals behind the all-time international record of 109 held by former Iran striker Ali Daei.
While the exact number of goals scored by some of the game’s legends is the subject of debate, Ronaldo is agreed to be the sixth player to reach 700 after Austrian Josef Bican, Brazilians Romario and Pele, Hungarian Ferenc Puskas and German Gerd Muller.